1 // Sun, 18 Jun 2000 2 // Y.Takagi 3 4 #include "IppTransport.h" 5 #include "DbgMsg.h" 6 7 #include <PrintTransportAddOn.h> 8 #include <NetEndpoint.h> 9 #include <String.h> 10 #include <OS.h> 11 12 #include <HashString.h> 13 #include <HashMap.h> 14 15 IppTransport *transport = NULL; 16 17 // Set transport_features so we stay loaded 18 uint32 transport_features = B_TRANSPORT_IS_HOTPLUG | B_TRANSPORT_IS_NETWORK; 19 20 21 class IPPPrinter { 22 public: 23 IPPPrinter(const BString& uri, uint32 type) 24 { fURI=uri; fType=type; } 25 26 uint32 fType, fState; 27 BString fURI, fLocation, fInfo, fMakeModel, fAttributes; 28 }; 29 30 31 class IPPPrinterRoster { 32 public: 33 IPPPrinterRoster(); 34 ~IPPPrinterRoster(); 35 36 status_t ListPorts(BMessage *msg); 37 status_t Listen(); 38 private: 39 char *_ParseString(BString& outStr, char*& pos); 40 41 static status_t _IPPListeningThread(void *cookie); 42 43 typedef HashMap<HashString,IPPPrinter*> IPPPrinterMap; 44 IPPPrinterMap fPrinters; 45 BNetEndpoint *fEndpoint; 46 thread_id fListenThreadID; 47 }; 48 49 50 static IPPPrinterRoster gRoster; 51 52 53 IPPPrinterRoster::IPPPrinterRoster() 54 { 55 // Setup our (UDP) listening endpoint 56 fEndpoint = new BNetEndpoint(SOCK_DGRAM); 57 if (!fEndpoint) 58 return; 59 60 if (fEndpoint->InitCheck() != B_OK) 61 return; 62 63 if (fEndpoint->Bind(BNetAddress(INADDR_ANY, 631)) != B_OK) 64 return; 65 66 // Now create thread for listening 67 fListenThreadID = spawn_thread(_IPPListeningThread, "IPPListener", B_LOW_PRIORITY, this); 68 if (fListenThreadID <= 0) 69 return; 70 71 resume_thread(fListenThreadID); 72 } 73 74 75 IPPPrinterRoster::~IPPPrinterRoster() 76 { 77 kill_thread(fListenThreadID); 78 delete fEndpoint; 79 } 80 81 82 status_t 83 IPPPrinterRoster::Listen() 84 { 85 BNetAddress srcAddress; 86 uint32 type, state; 87 char packet[1541]; 88 char uri[1024]; 89 char* pos; 90 int32 len; 91 92 while ((len=fEndpoint->ReceiveFrom(packet, sizeof(packet) -1, srcAddress)) > 0) { 93 packet[len] = '\0'; 94 95 // Verify packet format 96 if (sscanf(packet, "%" B_SCNx32 "%" B_SCNx32 "%1023s", &type, &state, 97 uri) == 3) { 98 IPPPrinter *printer = fPrinters.Get(uri); 99 if (!printer) { 100 printer = new IPPPrinter(uri, type); 101 fPrinters.Put(printer->fURI.String(), printer); 102 } 103 104 printer->fState=state; 105 106 // Check for option parameters 107 if ((pos=strchr(packet, '"')) != NULL) { 108 BString str; 109 if (_ParseString(str, pos)) 110 printer->fLocation = str; 111 if (pos && _ParseString(str, pos)) 112 printer->fInfo = str; 113 if (pos && _ParseString(str, pos)) 114 printer->fMakeModel = str; 115 116 if (pos) 117 printer->fAttributes = pos; 118 } 119 120 DBGMSG(("Printer: %s\nLocation: %s\nInfo: %s\nMakeModel: %s\nAttributes: %s\n", 121 printer->fURI.String(), printer->fLocation.String(), printer->fInfo.String(), 122 printer->fMakeModel.String(), printer->fAttributes.String())); 123 } 124 } 125 126 return len; 127 } 128 129 130 status_t 131 IPPPrinterRoster::ListPorts(BMessage* msg) 132 { 133 IPPPrinterMap::Iterator iterator = fPrinters.GetIterator(); 134 while (iterator.HasNext()) { 135 const IPPPrinterMap::Entry& entry = iterator.Next(); 136 msg->AddString("port_id", entry.value->fURI); 137 138 BString name = entry.value->fInfo; 139 if (name.Length() && entry.value->fLocation.Length()) { 140 name.Append(" ["); 141 name.Append(entry.value->fLocation); 142 name.Append("]"); 143 } 144 145 msg->AddString("port_name", name); 146 } 147 148 return B_OK; 149 } 150 151 152 char* 153 IPPPrinterRoster::_ParseString(BString& outStr, char*& pos) 154 { 155 outStr = ""; 156 157 if (*pos == '"') 158 pos++; 159 160 while(*pos && *pos != '"') 161 outStr.Append(*pos++, 1); 162 163 if (*pos == '"') 164 ++pos; 165 166 while(*pos && isspace(*pos)) 167 ++pos; 168 169 if (!*pos) 170 pos = NULL; 171 172 return pos; 173 } 174 175 176 status_t 177 IPPPrinterRoster::_IPPListeningThread(void *cookie) 178 { 179 return ((IPPPrinterRoster*)cookie)->Listen(); 180 } 181 182 183 // --- general transport hooks 184 185 extern "C" _EXPORT void 186 exit_transport() 187 { 188 DBGMSG(("> exit_transport\n")); 189 if (transport) { 190 delete transport; 191 transport = NULL; 192 } 193 DBGMSG(("< exit_transport\n")); 194 } 195 196 197 // List detected printers 198 extern "C" _EXPORT status_t 199 list_transport_ports(BMessage* msg) 200 { 201 return gRoster.ListPorts(msg); 202 } 203 204 205 extern "C" _EXPORT BDataIO * 206 init_transport(BMessage *msg) 207 { 208 DBGMSG(("> init_transport\n")); 209 210 transport = new IppTransport(msg); 211 212 if (transport->fail()) { 213 exit_transport(); 214 } 215 216 if (msg) 217 msg->what = 'okok'; 218 219 DBGMSG(("< init_transport\n")); 220 return transport; 221 } 222