1
2 /*
3 Meanwhile - Unofficial Lotus Sametime Community Client Library
4 Copyright (C) 2004 Christopher (siege) O'Brien
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with this library; if not, write to the Free
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <glib.h>
22
23 #include "mw_channel.h"
24 #include "mw_common.h"
25 #include "mw_debug.h"
26 #include "mw_error.h"
27 #include "mw_service.h"
28 #include "mw_session.h"
29 #include "mw_srvc_resolve.h"
30
31
32 #define PROTOCOL_TYPE 0x00000015
33 #define PROTOCOL_VER 0x00000000
34
35
36 /** oddly, there is only one message type in this service */
37 #define RESOLVE_ACTION 0x02
38
39
40 struct mwServiceResolve {
41 struct mwService service;
42
43 struct mwChannel *channel; /**< channel for this service */
44 GHashTable *searches; /**< guint32:struct mw_search */
45 guint32 counter; /**< incremented to provide searche IDs */
46 };
47
48
49 /** structure representing an active search. keeps track of the ID,
50 the handler, and the optional user data and cleanup */
51 struct mw_search {
52 struct mwServiceResolve *service;
53 guint32 id;
54 mwResolveHandler handler;
55 gpointer data;
56 GDestroyNotify cleanup;
57 };
58
59
search_new(struct mwServiceResolve * srvc,mwResolveHandler handler,gpointer data,GDestroyNotify cleanup)60 static struct mw_search *search_new(struct mwServiceResolve *srvc,
61 mwResolveHandler handler,
62 gpointer data, GDestroyNotify cleanup) {
63
64 struct mw_search *search = g_new0(struct mw_search, 1);
65
66 search->service = srvc;
67 search->handler = handler;
68
69 /* we want search IDs that aren't SEARCH_ERROR */
70 do {
71 search->id = srvc->counter++;
72 } while(search->id == SEARCH_ERROR);
73
74 search->data = data;
75 search->cleanup = cleanup;
76
77 return search;
78 }
79
80
81 /** called whenever a mw_search is removed from the searches table of
82 the service */
search_free(struct mw_search * search)83 static void search_free(struct mw_search *search) {
84 g_return_if_fail(search != NULL);
85
86 if(search->cleanup)
87 search->cleanup(search->data);
88
89 g_free(search);
90 }
91
92
get_name(struct mwService * srvc)93 static const char *get_name(struct mwService *srvc) {
94 return "Identity Resolution";
95 }
96
97
get_desc(struct mwService * srvc)98 static const char *get_desc(struct mwService *srvc) {
99 return "Resolves short IDs to full IDs";
100 }
101
102
make_channel(struct mwServiceResolve * srvc)103 static struct mwChannel *make_channel(struct mwServiceResolve *srvc) {
104 struct mwSession *session;
105 struct mwChannelSet *cs;
106 struct mwChannel *chan;
107
108 session = mwService_getSession(MW_SERVICE(srvc));
109 cs = mwSession_getChannels(session);
110 chan = mwChannel_newOutgoing(cs);
111
112 mwChannel_setService(chan, MW_SERVICE(srvc));
113 mwChannel_setProtoType(chan, PROTOCOL_TYPE);
114 mwChannel_setProtoVer(chan, PROTOCOL_VER);
115
116 return mwChannel_create(chan)? NULL: chan;
117 }
118
119
start(struct mwServiceResolve * srvc)120 static void start(struct mwServiceResolve *srvc) {
121 struct mwChannel *chan;
122
123 g_return_if_fail(srvc != NULL);
124
125 chan = make_channel(srvc);
126 if(chan) {
127 srvc->channel = chan;
128 } else {
129 mwService_stopped(MW_SERVICE(srvc));
130 return;
131 }
132
133 /* semi-lazily create the searches table */
134 srvc->searches = g_hash_table_new_full(g_direct_hash, g_direct_equal,
135 NULL, (GDestroyNotify) search_free);
136 }
137
138
stop(struct mwServiceResolve * srvc)139 static void stop(struct mwServiceResolve *srvc) {
140 g_return_if_fail(srvc != NULL);
141
142 if(srvc->channel) {
143 mwChannel_destroy(srvc->channel, ERR_SUCCESS, NULL);
144 srvc->channel = NULL;
145 }
146
147 /* destroy all the pending requests. */
148 g_hash_table_destroy(srvc->searches);
149 srvc->searches = NULL;
150
151 mwService_stopped(MW_SERVICE(srvc));
152 }
153
154
clear(struct mwServiceResolve * srvc)155 static void clear(struct mwServiceResolve *srvc) {
156 if(srvc->searches) {
157 g_hash_table_destroy(srvc->searches);
158 srvc->searches = NULL;
159 }
160 }
161
162
recv_create(struct mwServiceResolve * srvc,struct mwChannel * chan,struct mwMsgChannelCreate * msg)163 static void recv_create(struct mwServiceResolve *srvc,
164 struct mwChannel *chan,
165 struct mwMsgChannelCreate *msg) {
166
167 /* you serve me, not the other way around */
168 mwChannel_destroy(chan, ERR_FAILURE, NULL);
169 }
170
171
recv_accept(struct mwServiceResolve * srvc,struct mwChannel * chan,struct mwMsgChannelAccept * msg)172 static void recv_accept(struct mwServiceResolve *srvc,
173 struct mwChannel *chan,
174 struct mwMsgChannelAccept *msg) {
175
176 g_return_if_fail(srvc != NULL);
177 g_return_if_fail(chan != NULL);
178 g_return_if_fail(chan == srvc->channel);
179
180 mwService_started(MW_SERVICE(srvc));
181 }
182
183
recv_destroy(struct mwServiceResolve * srvc,struct mwChannel * chan,struct mwMsgChannelDestroy * msg)184 static void recv_destroy(struct mwServiceResolve *srvc,
185 struct mwChannel *chan,
186 struct mwMsgChannelDestroy *msg) {
187
188 struct mwSession *session;
189
190 g_return_if_fail(srvc != NULL);
191 g_return_if_fail(chan != NULL);
192 g_return_if_fail(chan == srvc->channel);
193
194 srvc->channel = NULL;
195 mwService_stop(MW_SERVICE(srvc));
196
197 session = mwService_getSession(MW_SERVICE(srvc));
198 g_return_if_fail(session != NULL);
199
200 mwSession_senseService(session, mwService_getType(MW_SERVICE(srvc)));
201 }
202
203
load_matches(struct mwGetBuffer * b,guint32 count)204 static GList *load_matches(struct mwGetBuffer *b, guint32 count) {
205 GList *matches = NULL;
206
207 while(count--) {
208 struct mwResolveMatch *m = g_new0(struct mwResolveMatch, 1);
209
210 mwString_get(b, &m->id);
211 mwString_get(b, &m->name);
212 mwString_get(b, &m->desc);
213 guint32_get(b, &m->type);
214
215 matches = g_list_append(matches, m);
216 }
217
218 return matches;
219 }
220
221
load_results(struct mwGetBuffer * b,guint32 count)222 static GList *load_results(struct mwGetBuffer *b, guint32 count) {
223 GList *results = NULL;
224
225 while(count--) {
226 struct mwResolveResult *r = g_new0(struct mwResolveResult, 1);
227 guint32 junk, matches;
228
229 guint32_get(b, &junk);
230 guint32_get(b, &r->code);
231 mwString_get(b, &r->name);
232
233 guint32_get(b, &matches);
234 r->matches = load_matches(b, matches);
235
236 results = g_list_append(results, r);
237 }
238
239 return results;
240 }
241
242
free_matches(GList * matches)243 static void free_matches(GList *matches) {
244 for(; matches; matches = g_list_delete_link(matches, matches)) {
245 struct mwResolveMatch *m = matches->data;
246 g_free(m->id);
247 g_free(m->name);
248 g_free(m->desc);
249 g_free(m);
250 }
251 }
252
253
free_results(GList * results)254 static void free_results(GList *results) {
255 for(; results; results = g_list_delete_link(results, results)) {
256 struct mwResolveResult *r = results->data;
257 g_free(r->name);
258 free_matches(r->matches);
259 g_free(r);
260 }
261 }
262
263
recv(struct mwServiceResolve * srvc,struct mwChannel * chan,guint16 type,struct mwOpaque * data)264 static void recv(struct mwServiceResolve *srvc,
265 struct mwChannel *chan,
266 guint16 type, struct mwOpaque *data) {
267
268 struct mwGetBuffer *b;
269 guint32 junk, id, code, count;
270 struct mw_search *search;
271
272 g_return_if_fail(srvc != NULL);
273 g_return_if_fail(chan != NULL);
274 g_return_if_fail(chan == srvc->channel);
275 g_return_if_fail(data != NULL);
276
277 if(type != RESOLVE_ACTION) {
278 mw_mailme_opaque(data, "unknown message in resolve service: 0x%04x", type);
279 return;
280 }
281
282 b = mwGetBuffer_wrap(data);
283 guint32_get(b, &junk);
284 guint32_get(b, &id);
285 guint32_get(b, &code);
286 guint32_get(b, &count);
287
288 if(mwGetBuffer_error(b)) {
289 g_warning("error parsing search result");
290 mwGetBuffer_free(b);
291 return;
292 }
293
294 search = g_hash_table_lookup(srvc->searches, GUINT_TO_POINTER(id));
295
296 if(search) {
297 GList *results = load_results(b, count);
298 if(mwGetBuffer_error(b)) {
299 g_warning("error parsing search results");
300 } else {
301 g_debug("triggering handler");
302 search->handler(srvc, id, code, results, search->data);
303 }
304 free_results(results);
305 g_hash_table_remove(srvc->searches, GUINT_TO_POINTER(id));
306
307 } else {
308 g_debug("no search found: 0x%x", id);
309 }
310
311 mwGetBuffer_free(b);
312 }
313
314
mwServiceResolve_new(struct mwSession * session)315 struct mwServiceResolve *mwServiceResolve_new(struct mwSession *session) {
316 struct mwServiceResolve *srvc_resolve;
317 struct mwService *srvc;
318
319 g_return_val_if_fail(session != NULL, NULL);
320
321 srvc_resolve = g_new0(struct mwServiceResolve, 1);
322
323 srvc = MW_SERVICE(srvc_resolve);
324
325 mwService_init(srvc, session, mwService_RESOLVE);
326 srvc->get_name = get_name;
327 srvc->get_desc = get_desc;
328 srvc->recv_create = (mwService_funcRecvCreate) recv_create;
329 srvc->recv_accept = (mwService_funcRecvAccept) recv_accept;
330 srvc->recv_destroy = (mwService_funcRecvDestroy) recv_destroy;
331 srvc->recv = (mwService_funcRecv) recv;
332 srvc->start = (mwService_funcStart) start;
333 srvc->stop = (mwService_funcStop) stop;
334 srvc->clear = (mwService_funcClear) clear;
335
336 return srvc_resolve;
337 }
338
339
mwServiceResolve_resolve(struct mwServiceResolve * srvc,GList * queries,enum mwResolveFlag flags,mwResolveHandler handler,gpointer data,GDestroyNotify cleanup)340 guint32 mwServiceResolve_resolve(struct mwServiceResolve *srvc,
341 GList *queries, enum mwResolveFlag flags,
342 mwResolveHandler handler,
343 gpointer data, GDestroyNotify cleanup) {
344
345 struct mw_search *search;
346 struct mwPutBuffer *b;
347 struct mwOpaque o = { 0, 0 };
348 int ret, count = 0;
349
350 g_return_val_if_fail(srvc != NULL, SEARCH_ERROR);
351 g_return_val_if_fail(handler != NULL, SEARCH_ERROR);
352
353 count = g_list_length(queries);
354 g_return_val_if_fail(count > 0, SEARCH_ERROR);
355
356 search = search_new(srvc, handler, data, cleanup);
357
358 b = mwPutBuffer_new();
359 guint32_put(b, 0x00); /* to be overwritten */
360 guint32_put(b, search->id);
361 guint32_put(b, count);
362 for(; queries; queries = queries->next)
363 mwString_put(b, queries->data);
364 guint32_put(b, flags);
365
366 mwPutBuffer_finalize(&o, b);
367
368 ret = mwChannel_send(srvc->channel, RESOLVE_ACTION, &o);
369 if(ret) {
370 search_free(search);
371 return SEARCH_ERROR;
372
373 } else {
374 g_hash_table_insert(srvc->searches,
375 GUINT_TO_POINTER(search->id), search);
376 return search->id;
377 }
378 }
379
380
mwServiceResolve_cancelResolve(struct mwServiceResolve * srvc,guint32 id)381 void mwServiceResolve_cancelResolve(struct mwServiceResolve *srvc,
382 guint32 id) {
383
384 g_return_if_fail(srvc != NULL);
385 g_return_if_fail(srvc->searches != NULL);
386
387 g_hash_table_remove(srvc->searches, GUINT_TO_POINTER(id));
388 }
389
390