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, µ);
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