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 <stdio.h>
22 #include <string.h>
23 #include <glib.h>
24 
25 #include "mw_debug.h"
26 #include "mw_util.h"
27 #include "mw_st_list.h"
28 
29 
30 struct mwSametimeList {
31   guint ver_major;
32   guint ver_minor;
33   guint ver_micro;
34 
35   GList *groups;
36 };
37 
38 
39 struct mwSametimeGroup {
40   struct mwSametimeList *list;
41 
42   enum mwSametimeGroupType type;
43   char *name;
44   char *alias;
45   gboolean open;
46 
47   GList *users;
48 };
49 
50 
51 struct mwSametimeUser {
52   struct mwSametimeGroup *group;
53 
54   enum mwSametimeUserType type;
55   struct mwIdBlock id;
56   char *name;
57   char *alias;
58 };
59 
60 
user_free(struct mwSametimeUser * u)61 static void user_free(struct mwSametimeUser *u) {
62   struct mwSametimeGroup *g;
63 
64   g = u->group;
65   g->users = g_list_remove(g->users, u);
66 
67   mwIdBlock_clear(&u->id);
68   g_free(u->name);
69   g_free(u->alias);
70   g_free(u);
71 }
72 
73 
group_free(struct mwSametimeGroup * g)74 static void group_free(struct mwSametimeGroup *g) {
75   struct mwSametimeList *l;
76 
77   l = g->list;
78   l->groups = g_list_remove(l->groups, g);
79 
80   while(g->users)
81     mwSametimeUser_free(g->users->data);
82 
83   g_free(g->name);
84   g_free(g->alias);
85   g_free(g);
86 }
87 
88 
list_free(struct mwSametimeList * l)89 static void list_free(struct mwSametimeList *l) {
90   while(l->groups)
91     mwSametimeGroup_free(l->groups->data);
92 
93   g_free(l);
94 }
95 
96 
97 struct mwSametimeList *
mwSametimeList_new()98 mwSametimeList_new() {
99 
100   struct mwSametimeList *stl;
101 
102   stl = g_new0(struct mwSametimeList, 1);
103   stl->ver_major = ST_LIST_MAJOR;
104   stl->ver_minor = ST_LIST_MINOR;
105   stl->ver_micro = ST_LIST_MICRO;
106 
107   return stl;
108 }
109 
110 
mwSametimeList_setMajor(struct mwSametimeList * l,guint v)111 void mwSametimeList_setMajor(struct mwSametimeList *l, guint v) {
112   g_return_if_fail(l != NULL);
113   l->ver_major = v;
114 }
115 
116 
mwSametimeList_getMajor(struct mwSametimeList * l)117 guint mwSametimeList_getMajor(struct mwSametimeList *l) {
118   g_return_val_if_fail(l != NULL, 0);
119   return l->ver_major;
120 }
121 
122 
mwSametimeList_setMinor(struct mwSametimeList * l,guint v)123 void mwSametimeList_setMinor(struct mwSametimeList *l, guint v) {
124   g_return_if_fail(l != NULL);
125   l->ver_minor = v;
126 }
127 
128 
mwSametimeList_getMinor(struct mwSametimeList * l)129 guint mwSametimeList_getMinor(struct mwSametimeList *l) {
130   g_return_val_if_fail(l != NULL, 0);
131   return l->ver_minor;
132 }
133 
134 
mwSametimeList_setMicro(struct mwSametimeList * l,guint v)135 void mwSametimeList_setMicro(struct mwSametimeList *l, guint v) {
136   g_return_if_fail(l != NULL);
137   l->ver_micro = v;
138 }
139 
140 
mwSametimeList_getMicro(struct mwSametimeList * l)141 guint mwSametimeList_getMicro(struct mwSametimeList *l) {
142   g_return_val_if_fail(l != NULL, 0);
143   return l->ver_micro;
144 }
145 
146 
mwSametimeList_getGroups(struct mwSametimeList * l)147 GList *mwSametimeList_getGroups(struct mwSametimeList *l) {
148   g_return_val_if_fail(l != NULL, NULL);
149   return g_list_copy(l->groups);
150 }
151 
152 
153 struct mwSametimeGroup *
mwSametimeList_findGroup(struct mwSametimeList * l,const char * name)154 mwSametimeList_findGroup(struct mwSametimeList *l,
155 			 const char *name) {
156   GList *s;
157 
158   g_return_val_if_fail(l != NULL, NULL);
159   g_return_val_if_fail(name != NULL, NULL);
160   g_return_val_if_fail(*name != '\0', NULL);
161 
162   for(s = l->groups; s; s = s->next) {
163     struct mwSametimeGroup *g = s->data;
164     if(! strcmp(g->name, name)) return g;
165   }
166 
167   return NULL;
168 }
169 
170 
mwSametimeList_free(struct mwSametimeList * l)171 void mwSametimeList_free(struct mwSametimeList *l) {
172   g_return_if_fail(l != NULL);
173   list_free(l);
174 }
175 
176 
177 struct mwSametimeGroup *
mwSametimeGroup_new(struct mwSametimeList * list,enum mwSametimeGroupType type,const char * name)178 mwSametimeGroup_new(struct mwSametimeList *list,
179 		    enum mwSametimeGroupType type,
180 		    const char *name) {
181 
182   struct mwSametimeGroup *stg;
183 
184   g_return_val_if_fail(list != NULL, NULL);
185   g_return_val_if_fail(name != NULL, NULL);
186   g_return_val_if_fail(*name != '\0', NULL);
187 
188   stg = g_new0(struct mwSametimeGroup, 1);
189   stg->list = list;
190   stg->type = type;
191   stg->name = g_strdup(name);
192 
193   list->groups = g_list_append(list->groups, stg);
194 
195   return stg;
196 }
197 
198 
mwSametimeGroup_getType(struct mwSametimeGroup * g)199 enum mwSametimeGroupType mwSametimeGroup_getType(struct mwSametimeGroup *g) {
200   g_return_val_if_fail(g != NULL, mwSametimeGroup_UNKNOWN);
201   return g->type;
202 }
203 
204 
mwSametimeGroup_getName(struct mwSametimeGroup * g)205 const char *mwSametimeGroup_getName(struct mwSametimeGroup *g) {
206   g_return_val_if_fail(g != NULL, NULL);
207   return g->name;
208 }
209 
210 
mwSametimeGroup_setAlias(struct mwSametimeGroup * g,const char * alias)211 void mwSametimeGroup_setAlias(struct mwSametimeGroup *g,
212 			      const char *alias) {
213   g_return_if_fail(g != NULL);
214 
215   g_free(g->alias);
216   g->alias = g_strdup(alias);
217 }
218 
219 
mwSametimeGroup_getAlias(struct mwSametimeGroup * g)220 const char *mwSametimeGroup_getAlias(struct mwSametimeGroup *g) {
221   g_return_val_if_fail(g != NULL, NULL);
222   return g->alias;
223 }
224 
225 
mwSametimeGroup_setOpen(struct mwSametimeGroup * g,gboolean open)226 void mwSametimeGroup_setOpen(struct mwSametimeGroup *g, gboolean open) {
227   g_return_if_fail(g != NULL);
228   g->open = open;
229 }
230 
231 
mwSametimeGroup_isOpen(struct mwSametimeGroup * g)232 gboolean mwSametimeGroup_isOpen(struct mwSametimeGroup *g) {
233   g_return_val_if_fail(g != NULL, FALSE);
234   return g->open;
235 }
236 
237 
mwSametimeGroup_getList(struct mwSametimeGroup * g)238 struct mwSametimeList *mwSametimeGroup_getList(struct mwSametimeGroup *g) {
239   g_return_val_if_fail(g != NULL, NULL);
240   return g->list;
241 }
242 
243 
mwSametimeGroup_getUsers(struct mwSametimeGroup * g)244 GList *mwSametimeGroup_getUsers(struct mwSametimeGroup *g) {
245   g_return_val_if_fail(g != NULL, NULL);
246   return g_list_copy(g->users);
247 }
248 
249 
250 struct mwSametimeUser *
mwSametimeGroup_findUser(struct mwSametimeGroup * g,struct mwIdBlock * user)251 mwSametimeGroup_findUser(struct mwSametimeGroup *g,
252 			 struct mwIdBlock *user) {
253   GList *s;
254 
255   g_return_val_if_fail(g != NULL, NULL);
256   g_return_val_if_fail(user != NULL, NULL);
257 
258   for(s = g->users; s; s = s->next) {
259     struct mwSametimeUser *u = s->data;
260     if(mwIdBlock_equal(user, &u->id)) return u;
261   }
262 
263   return NULL;
264 }
265 
266 
mwSametimeGroup_free(struct mwSametimeGroup * g)267 void mwSametimeGroup_free(struct mwSametimeGroup *g) {
268   g_return_if_fail(g != NULL);
269   g_return_if_fail(g->list != NULL);
270   group_free(g);
271 }
272 
273 
274 struct mwSametimeUser *
mwSametimeUser_new(struct mwSametimeGroup * group,enum mwSametimeUserType type,struct mwIdBlock * id)275 mwSametimeUser_new(struct mwSametimeGroup *group,
276 		   enum mwSametimeUserType type,
277 		   struct mwIdBlock *id) {
278 
279   struct mwSametimeUser *stu;
280 
281   g_return_val_if_fail(group != NULL, NULL);
282   g_return_val_if_fail(id != NULL, NULL);
283 
284   stu = g_new0(struct mwSametimeUser, 1);
285   stu->group = group;
286   stu->type = type;
287   mwIdBlock_clone(&stu->id, id);
288 
289   group->users = g_list_append(group->users, stu);
290 
291   return stu;
292 }
293 
294 
mwSametimeUser_getGroup(struct mwSametimeUser * u)295 struct mwSametimeGroup *mwSametimeUser_getGroup(struct mwSametimeUser *u) {
296   g_return_val_if_fail(u != NULL, NULL);
297   return u->group;
298 }
299 
300 
mwSametimeUser_getType(struct mwSametimeUser * u)301 enum mwSametimeUserType mwSametimeUser_getType(struct mwSametimeUser *u) {
302   g_return_val_if_fail(u != NULL, mwSametimeUser_UNKNOWN);
303   return u->type;
304 }
305 
306 
mwSametimeUser_getUser(struct mwSametimeUser * u)307 const char *mwSametimeUser_getUser(struct mwSametimeUser *u) {
308   g_return_val_if_fail(u != NULL, NULL);
309   return u->id.user;
310 }
311 
312 
mwSametimeUser_getCommunity(struct mwSametimeUser * u)313 const char *mwSametimeUser_getCommunity(struct mwSametimeUser *u) {
314   g_return_val_if_fail(u != NULL, NULL);
315   return u->id.community;
316 }
317 
318 
mwSametimeUser_setShortName(struct mwSametimeUser * u,const char * name)319 void mwSametimeUser_setShortName(struct mwSametimeUser *u, const char *name) {
320   g_return_if_fail(u != NULL);
321   g_free(u->name);
322   u->name = g_strdup(name);
323 }
324 
325 
mwSametimeUser_getShortName(struct mwSametimeUser * u)326 const char *mwSametimeUser_getShortName(struct mwSametimeUser *u) {
327   g_return_val_if_fail(u != NULL, NULL);
328   return u->name;
329 }
330 
331 
mwSametimeUser_setAlias(struct mwSametimeUser * u,const char * alias)332 void mwSametimeUser_setAlias(struct mwSametimeUser *u, const char *alias) {
333   g_return_if_fail(u != NULL);
334   g_free(u->alias);
335   u->alias = g_strdup(alias);
336 }
337 
338 
mwSametimeUser_getAlias(struct mwSametimeUser * u)339 const char *mwSametimeUser_getAlias(struct mwSametimeUser *u) {
340   g_return_val_if_fail(u != NULL, NULL);
341   return u->alias;
342 }
343 
344 
mwSametimeUser_free(struct mwSametimeUser * u)345 void mwSametimeUser_free(struct mwSametimeUser *u) {
346   g_return_if_fail(u != NULL);
347   g_return_if_fail(u->group != NULL);
348   user_free(u);
349 }
350 
351 
str_replace(char * str,char from,char to)352 static void str_replace(char *str, char from, char to) {
353   if(! str) return;
354   for(; *str; str++) if(*str == from) *str = to;
355 }
356 
357 
user_type_to_char(enum mwSametimeUserType type)358 static char user_type_to_char(enum mwSametimeUserType type) {
359   switch(type) {
360   case mwSametimeUser_NORMAL:    return '1';
361   case mwSametimeUser_EXTERNAL:  return '2';
362   case mwSametimeUser_UNKNOWN:
363   default:                       return '9';
364   }
365 }
366 
367 
user_char_to_type(char type)368 static enum mwSametimeUserType user_char_to_type(char type) {
369   switch(type) {
370   case '1':  return mwSametimeUser_NORMAL;
371   case '2':  return mwSametimeUser_EXTERNAL;
372   default:   return mwSametimeUser_UNKNOWN;
373   }
374 }
375 
376 
user_put(GString * str,struct mwSametimeUser * u)377 static void user_put(GString *str, struct mwSametimeUser *u) {
378   char *id, *name, *alias;
379   char type;
380 
381   id = g_strdup(u->id.user);
382   name = g_strdup(u->name);
383   alias = g_strdup(u->alias);
384   type = user_type_to_char(u->type);
385 
386   if(id) str_replace(id, ' ', ';');
387   if(name) str_replace(name, ' ', ';');
388   if(alias) str_replace(alias, ' ', ';');
389 
390   if(!name && alias) {
391     name = alias;
392     alias = NULL;
393   }
394 
395   g_string_append_printf(str, "U %s%c:: %s,%s\r\n",
396 			 id, type, (name? name: ""), (alias? alias: ""));
397 
398   g_free(id);
399   g_free(name);
400   g_free(alias);
401 }
402 
403 
group_type_to_char(enum mwSametimeGroupType type)404 static char group_type_to_char(enum mwSametimeGroupType type) {
405   switch(type) {
406   case mwSametimeGroup_NORMAL:   return '2';
407   case mwSametimeGroup_DYNAMIC:  return '3';
408   case mwSametimeGroup_UNKNOWN:
409   default:                       return '9';
410   }
411 }
412 
413 
group_char_to_type(char type)414 static enum mwSametimeGroupType group_char_to_type(char type) {
415   switch(type) {
416   case '2':  return mwSametimeGroup_NORMAL;
417   case '3':  return mwSametimeGroup_DYNAMIC;
418   default:   return mwSametimeGroup_UNKNOWN;
419   }
420 }
421 
422 
group_put(GString * str,struct mwSametimeGroup * g)423 static void group_put(GString *str, struct mwSametimeGroup *g) {
424   char *name, *alias;
425   char type;
426   GList *gl;
427 
428   name = g_strdup(g->name);
429   alias = g_strdup((g->alias)? g->alias: name);
430   type = group_type_to_char(g->type);
431 
432   str_replace(name, ' ', ';');
433   str_replace(alias, ' ', ';');
434 
435   g_string_append_printf(str, "G %s%c %s %c\r\n",
436 			 name, type, alias, (g->open? 'O':'C'));
437 
438   for(gl = g->users; gl; gl = gl->next) {
439     user_put(str, gl->data);
440   }
441 
442   g_free(name);
443   g_free(alias);
444 }
445 
446 
447 /** composes a GString with the written contents of a sametime list */
list_store(struct mwSametimeList * l)448 static GString *list_store(struct mwSametimeList *l) {
449   GString *str;
450   GList *gl;
451 
452   g_return_val_if_fail(l != NULL, NULL);
453 
454   str = g_string_new(NULL);
455   g_string_append_printf(str, "Version=%u.%u.%u\r\n",
456 			 l->ver_major, l->ver_minor, l->ver_micro);
457 
458   for(gl = l->groups; gl; gl = gl->next) {
459     group_put(str, gl->data);
460   }
461 
462   return str;
463 }
464 
465 
mwSametimeList_store(struct mwSametimeList * l)466 char *mwSametimeList_store(struct mwSametimeList *l) {
467   GString *str;
468   char *s;
469 
470   g_return_val_if_fail(l != NULL, NULL);
471 
472   str = list_store(l);
473   s = str->str;
474   g_string_free(str, FALSE);
475   return s;
476 }
477 
478 
mwSametimeList_put(struct mwPutBuffer * b,struct mwSametimeList * l)479 void mwSametimeList_put(struct mwPutBuffer *b, struct mwSametimeList *l) {
480   GString *str;
481   guint16 len;
482 
483   g_return_if_fail(l != NULL);
484   g_return_if_fail(b != NULL);
485 
486   str = list_store(l);
487   len = (guint16) str->len;
488   guint16_put(b, len);
489   mwPutBuffer_write(b, str->str, len);
490 
491   g_string_free(str, TRUE);
492 }
493 
494 
get_version(const char * line,struct mwSametimeList * l)495 static void get_version(const char *line, struct mwSametimeList *l) {
496   guint major = 0, minor = 0, micro = 0;
497   int ret;
498 
499   ret = sscanf(line, "Version=%u.%u.%u\n", &major, &minor, &micro);
500   if(ret != 3) {
501     g_warning("strange sametime list version line:\n%s", line);
502   }
503 
504   l->ver_major = major;
505   l->ver_minor = minor;
506   l->ver_micro = micro;
507 }
508 
509 
get_group(const char * line,struct mwSametimeList * l)510 static struct mwSametimeGroup *get_group(const char *line,
511 					 struct mwSametimeList *l) {
512   struct mwSametimeGroup *group;
513   char *name, *alias;
514   char type = '2', open = 'O';
515   int ret;
516 
517   ret = strlen(line);
518   name = g_malloc0(ret);
519   alias = g_malloc0(ret);
520 
521   ret = sscanf(line, "G %s %s %c\n",
522 	       name, alias, &open);
523 
524   if(ret < 3) {
525     g_warning("strange sametime list group line:\n%s", line);
526   }
527 
528   str_replace(name, ';', ' ');
529   str_replace(alias, ';', ' ');
530 
531   if(name && *name) {
532     int l = strlen(name)-1;
533     type = name[l];
534     name[l] = '\0';
535   }
536 
537   group = g_new0(struct mwSametimeGroup, 1);
538   group->list = l;
539   group->name = name;
540   group->type = group_char_to_type(type);
541   group->alias = alias;
542   group->open = (open == 'O');
543 
544   l->groups = g_list_append(l->groups, group);
545 
546   return group;
547 }
548 
549 
get_user(const char * line,struct mwSametimeGroup * g)550 static void get_user(const char *line, struct mwSametimeGroup *g) {
551   struct mwSametimeUser *user;
552   struct mwIdBlock idb = { 0, 0 };
553   char *name, *alias = NULL;
554   char type = '1';
555   int ret;
556 
557   ret = strlen(line);
558   idb.user = g_malloc0(ret);
559   name = g_malloc0(ret);
560 
561   ret = sscanf(line, "U %s %s",
562 	       idb.user, name);
563 
564   if(ret < 2) {
565     g_warning("strange sametime list user line:\n%s", line);
566   }
567 
568   str_replace(idb.user, ';', ' ');
569   str_replace(name, ';', ' ');
570 
571   if(idb.user && *idb.user) {
572     char *tmp = strstr(idb.user, "::");
573     if(tmp--) {
574       type = *(tmp);
575       *tmp = '\0';
576     }
577   }
578 
579   if(name && *name) {
580     char *tmp = strrchr(name, ',');
581     if(tmp) {
582       *tmp++ = '\0';
583       if(*tmp) alias = tmp;
584     }
585   }
586 
587   user = g_new0(struct mwSametimeUser, 1);
588   user->group = g;
589   user->id.user = idb.user;
590   user->type = user_char_to_type(type);
591   user->name = name;
592   user->alias = g_strdup(alias);
593 
594   g->users = g_list_append(g->users, user);
595 }
596 
597 
598 /** returns a line from str, and advances str */
fetch_line(char ** str)599 static char *fetch_line(char **str) {
600   char *start = *str;
601   char *end;
602 
603   /* move to first non-whitespace character */
604   while(*start && g_ascii_isspace(*start)) start++;
605   if(! *start) return NULL;
606 
607   for(end = start + 1; *end; end++) {
608     if(*end == '\n' || *end == '\r') {
609       *(end++) = '\0';
610       break;
611     }
612   }
613 
614   *str = end;
615   return start;
616 }
617 
618 
list_get(const char * lines,struct mwSametimeList * l)619 static void list_get(const char *lines, struct mwSametimeList *l) {
620   char *s = (char *) lines;
621   char *line;
622 
623   struct mwSametimeGroup *g = NULL;
624 
625   while( (line = fetch_line(&s)) ) {
626     switch(*line) {
627     case 'V':
628       get_version(line, l);
629       break;
630 
631     case 'G':
632       g = get_group(line, l);
633       break;
634 
635     case 'U':
636       get_user(line, g);
637       break;
638 
639     default:
640       g_warning("unknown sametime list data line:\n%s", line);
641     }
642   }
643 }
644 
645 
mwSametimeList_load(const char * data)646 struct mwSametimeList *mwSametimeList_load(const char *data) {
647   struct mwSametimeList *l;
648 
649   g_return_val_if_fail(data != NULL, NULL);
650 
651   l = mwSametimeList_new();
652   list_get(data, l);
653 
654   return l;
655 }
656 
657 
mwSametimeList_get(struct mwGetBuffer * b,struct mwSametimeList * l)658 void mwSametimeList_get(struct mwGetBuffer *b, struct mwSametimeList *l) {
659   char *str = NULL;
660 
661   g_return_if_fail(l != NULL);
662   g_return_if_fail(b != NULL);
663 
664   mwString_get(b, &str);
665   list_get(str, l);
666   g_free(str);
667 }
668 
669