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