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:
IPPPrinter(const BString & uri,uint32 type)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
IPPPrinterRoster()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
~IPPPrinterRoster()75 IPPPrinterRoster::~IPPPrinterRoster()
76 {
77 kill_thread(fListenThreadID);
78 delete fEndpoint;
79 }
80
81
82 status_t
Listen()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
ListPorts(BMessage * msg)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*
_ParseString(BString & outStr,char * & pos)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
_IPPListeningThread(void * cookie)177 IPPPrinterRoster::_IPPListeningThread(void *cookie)
178 {
179 return ((IPPPrinterRoster*)cookie)->Listen();
180 }
181
182
183 // --- general transport hooks
184
185 extern "C" _EXPORT void
exit_transport()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
list_transport_ports(BMessage * msg)199 list_transport_ports(BMessage* msg)
200 {
201 return gRoster.ListPorts(msg);
202 }
203
204
205 extern "C" _EXPORT BDataIO *
init_transport(BMessage * msg)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