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[256]; 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, "%lx%lx%1023s", &type, &state, uri) == 3) { 97 IPPPrinter *printer = fPrinters.Get(uri); 98 if (!printer) { 99 printer = new IPPPrinter(uri, type); 100 fPrinters.Put(printer->fURI.String(), printer); 101 } 102 103 printer->fState=state; 104 105 // Check for option parameters 106 if ((pos=strchr(packet, '"')) != NULL) { 107 BString str; 108 if (_ParseString(str, pos)) 109 printer->fLocation = str; 110 if (pos && _ParseString(str, pos)) 111 printer->fInfo = str; 112 if (pos && _ParseString(str, pos)) 113 printer->fMakeModel = str; 114 115 if (pos) 116 printer->fAttributes = pos; 117 } 118 119 DBGMSG(("Printer: %s\nLocation: %s\nInfo: %s\nMakeModel: %s\nAttributes: %s\n", 120 printer->fURI.String(), printer->fLocation.String(), printer->fInfo.String(), 121 printer->fMakeModel.String(), printer->fAttributes.String())); 122 } 123 } 124 125 return len; 126 } 127 128 129 status_t 130 IPPPrinterRoster::ListPorts(BMessage* msg) 131 { 132 IPPPrinterMap::Iterator iterator = fPrinters.GetIterator(); 133 while (iterator.HasNext()) { 134 const IPPPrinterMap::Entry& entry = iterator.Next(); 135 msg->AddString("port_id", entry.value->fURI); 136 137 BString name = entry.value->fInfo; 138 if (name.Length() && entry.value->fLocation.Length()) { 139 name.Append(" ["); 140 name.Append(entry.value->fLocation); 141 name.Append("]"); 142 } 143 144 msg->AddString("port_name", name); 145 } 146 147 return B_OK; 148 } 149 150 151 char* 152 IPPPrinterRoster::_ParseString(BString& outStr, char*& pos) 153 { 154 outStr = ""; 155 156 if (*pos == '"') 157 pos++; 158 159 while(*pos && *pos != '"') 160 outStr.Append(*pos++, 1); 161 162 if (*pos == '"') 163 ++pos; 164 165 while(*pos && isspace(*pos)) 166 ++pos; 167 168 if (!*pos) 169 pos = NULL; 170 171 return pos; 172 } 173 174 175 status_t 176 IPPPrinterRoster::_IPPListeningThread(void *cookie) 177 { 178 return ((IPPPrinterRoster*)cookie)->Listen(); 179 } 180 181 182 // --- general transport hooks 183 184 extern "C" _EXPORT void 185 exit_transport() 186 { 187 DBGMSG(("> exit_transport\n")); 188 if (transport) { 189 delete transport; 190 transport = NULL; 191 } 192 DBGMSG(("< exit_transport\n")); 193 } 194 195 196 // List detected printers 197 extern "C" _EXPORT status_t 198 list_transport_ports(BMessage* msg) 199 { 200 return gRoster.ListPorts(msg); 201 } 202 203 204 extern "C" _EXPORT BDataIO * 205 init_transport(BMessage *msg) 206 { 207 DBGMSG(("> init_transport\n")); 208 209 transport = new IppTransport(msg); 210 211 if (transport->fail()) { 212 exit_transport(); 213 } 214 215 if (msg) 216 msg->what = 'okok'; 217 218 DBGMSG(("< init_transport\n")); 219 return transport; 220 } 221