comparison src/list.c @ 2382:569ae9f2bb89

[gaim-migrate @ 2395] big reorg of code. list.c contains 0 gtk. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Fri, 28 Sep 2001 07:46:36 +0000
parents
children 413a81136e3a
comparison
equal deleted inserted replaced
2381:427ccd7dfdd2 2382:569ae9f2bb89
1 /*
2 * gaim
3 *
4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include "gaim.h"
30 #include "prpl.h"
31
32 #define PATHSIZE 1024
33
34 void remove_buddy(struct gaim_connection *gc, struct group *rem_g, struct buddy *rem_b)
35 {
36 GSList *grp;
37 GSList *mem;
38
39 struct group *delg;
40 struct buddy *delb;
41
42 /* we assume that gc is not NULL and that the buddy exists somewhere within the
43 * gc's buddy list, therefore we can safely remove it. we need to ensure this
44 * via the UI
45 */
46
47 grp = g_slist_find(gc->groups, rem_g);
48 delg = (struct group *)grp->data;
49 mem = delg->members;
50
51 mem = g_slist_find(mem, rem_b);
52 delb = (struct buddy *)mem->data;
53
54 delg->members = g_slist_remove(delg->members, delb);
55
56 ui_remove_buddy(gc, rem_g, rem_b);
57
58 g_free(rem_b);
59
60 /* we don't flush buddy list to cache because in the case of remove_group that would
61 * mean writing to the buddy list file once for each buddy, plus one more time */
62 }
63
64 void remove_group(struct gaim_connection *gc, struct group *rem_g)
65 {
66 GSList *grp;
67 GSList *mem;
68 GList *tmp = NULL;
69
70 struct group *delg;
71 struct buddy *delb;
72
73 /* we assume that the group actually does exist within the gc, and that the gc is not NULL.
74 * the UI is responsible for this */
75
76 grp = g_slist_find(gc->groups, rem_g);
77 delg = (struct group *)grp->data;
78 mem = delg->members;
79
80 while (delg->members) {
81 delb = (struct buddy *)delg->members->data;
82 tmp = g_list_append(tmp, g_strdup(delb->name));
83 remove_buddy(gc, delg, delb); /* this should take care of removing
84 the group_show if necessary */
85 }
86
87 gc->groups = g_slist_remove(gc->groups, delg);
88
89 serv_remove_buddies(gc, tmp);
90 while (tmp) {
91 g_free(tmp->data);
92 tmp = g_list_remove(tmp, tmp->data);
93 }
94
95 ui_remove_group(gc, rem_g);
96
97 g_free(rem_g);
98
99 /* don't flush buddy list to cache in order to be consistent with remove_buddy,
100 * mostly. remove_group is only called from one place, so we'll let it handle it. */
101 }
102
103 struct buddy *add_buddy(struct gaim_connection *gc, char *group, char *buddy, char *show)
104 {
105 struct buddy *b;
106 struct group *g;
107 char *good;
108
109 if ((b = find_buddy(gc, buddy)) != NULL)
110 return b;
111
112 g = find_group(gc, group);
113
114 if (g == NULL)
115 g = add_group(gc, group);
116
117 b = (struct buddy *)g_new0(struct buddy, 1);
118
119 if (!b)
120 return NULL;
121
122 b->gc = gc;
123 b->present = 0;
124
125 if (gc->prpl->normalize)
126 good = (*gc->prpl->normalize)(buddy);
127 else
128 good = buddy;
129
130 g_snprintf(b->name, sizeof(b->name), "%s", good);
131 g_snprintf(b->show, sizeof(b->show), "%s", show ? (show[0] ? show : good) : good);
132
133 g->members = g_slist_append(g->members, b);
134
135 b->idle = 0;
136 b->caps = 0;
137
138 ui_add_buddy(gc, g, b);
139
140 return b;
141 }
142
143 struct group *add_group(struct gaim_connection *gc, char *group)
144 {
145 struct group *g = find_group(gc, group);
146 if (g)
147 return g;
148 g = (struct group *)g_new0(struct group, 1);
149 if (!g)
150 return NULL;
151
152 g->gc = gc;
153 strncpy(g->name, group, sizeof(g->name));
154 gc->groups = g_slist_append(gc->groups, g);
155
156 g->members = NULL;
157
158 ui_add_group(gc, g);
159
160 return g;
161 }
162
163 struct group *find_group(struct gaim_connection *gc, char *group)
164 {
165 struct group *g;
166 GSList *grp;
167 GSList *c = connections;
168 struct gaim_connection *z;
169 char *grpname = g_malloc(strlen(group) + 1);
170
171 strcpy(grpname, normalize (group));
172 if (gc) {
173 grp = gc->groups;
174 while (grp) {
175 g = (struct group *)grp->data;
176 if (!g_strcasecmp(normalize (g->name), grpname)) {
177 g_free(grpname);
178 return g;
179 }
180 grp = g_slist_next(grp);
181 }
182
183 g_free(grpname);
184 return NULL;
185 } else {
186 while (c) {
187 z = (struct gaim_connection *)c->data;
188 grp = z->groups;
189 while (grp) {
190 g = (struct group *)grp->data;
191 if (!g_strcasecmp(normalize (g->name), grpname)) {
192 g_free(grpname);
193 return g;
194 }
195 grp = g_slist_next(grp);
196 }
197
198 c = c->next;
199 }
200 g_free(grpname);
201 return NULL;
202 }
203 }
204
205 struct group *find_group_by_buddy(struct gaim_connection *gc, char *who)
206 {
207 struct group *g;
208 struct buddy *b;
209 GSList *grp;
210 GSList *mem;
211 char *whoname;
212 char *(*norm)(const char *);
213
214 if (gc) {
215 if (gc->prpl->normalize)
216 norm = gc->prpl->normalize;
217 else
218 norm = normalize;
219 whoname = g_strdup((*norm)(who));
220 grp = gc->groups;
221 while (grp) {
222 g = (struct group *)grp->data;
223
224 mem = g->members;
225 while (mem) {
226 b = (struct buddy *)mem->data;
227 if (!strcmp((*norm)(b->name), whoname)) {
228 g_free(whoname);
229 return g;
230 }
231 mem = mem->next;
232 }
233 grp = g_slist_next(grp);
234 }
235 g_free(whoname);
236 return NULL;
237 } else {
238 GSList *c = connections;
239 struct gaim_connection *z;
240 while (c) {
241 z = (struct gaim_connection *)c->data;
242 if (z->prpl->normalize)
243 norm = z->prpl->normalize;
244 else
245 norm = normalize;
246 whoname = g_strdup((*norm)(who));
247 grp = z->groups;
248 while (grp) {
249 g = (struct group *)grp->data;
250
251 mem = g->members;
252 while (mem) {
253 b = (struct buddy *)mem->data;
254 if (!strcmp((*norm)(b->name), whoname)) {
255 g_free(whoname);
256 return g;
257 }
258 mem = mem->next;
259 }
260 grp = g_slist_next(grp);
261 }
262 c = c->next;
263 g_free(whoname);
264 }
265 return NULL;
266 }
267 }
268
269 struct buddy *find_buddy(struct gaim_connection *gc, char *who)
270 {
271 struct group *g;
272 struct buddy *b;
273 GSList *grp;
274 GSList *c;
275 struct gaim_connection *z;
276 GSList *mem;
277 char *whoname;
278 char *(*norm)(const char *);
279
280 if (gc) {
281 if (gc->prpl->normalize)
282 norm = gc->prpl->normalize;
283 else
284 norm = normalize;
285 whoname = g_strdup((*norm)(who));
286 grp = gc->groups;
287 while (grp) {
288 g = (struct group *)grp->data;
289
290 mem = g->members;
291 while (mem) {
292 b = (struct buddy *)mem->data;
293 if (!strcmp((*norm)(b->name), whoname)) {
294 g_free(whoname);
295 return b;
296 }
297 mem = mem->next;
298 }
299 grp = g_slist_next(grp);
300 }
301 g_free(whoname);
302 return NULL;
303 } else {
304 c = connections;
305 while (c) {
306 z = (struct gaim_connection *)c->data;
307 if (z->prpl->normalize)
308 norm = z->prpl->normalize;
309 else
310 norm = normalize;
311 whoname = g_strdup((*norm)(who));
312 grp = z->groups;
313 while (grp) {
314 g = (struct group *)grp->data;
315
316 mem = g->members;
317 while (mem) {
318 b = (struct buddy *)mem->data;
319 if (!strcmp((*norm)(b->name), whoname)) {
320 g_free(whoname);
321 return b;
322 }
323 mem = mem->next;
324 }
325 grp = g_slist_next(grp);
326 }
327 c = c->next;
328 g_free(whoname);
329 }
330 return NULL;
331 }
332 }
333
334 void parse_toc_buddy_list(struct gaim_connection *gc, char *config, int from_do_import)
335 {
336 char *c;
337 char current[256];
338 char *name;
339 GList *bud;
340 int how_many = 0;
341
342 bud = NULL;
343
344 if (config != NULL) {
345
346 /* skip "CONFIG:" (if it exists) */
347 c = strncmp(config + 6 /* sizeof(struct sflap_hdr) */ , "CONFIG:", strlen("CONFIG:")) ?
348 strtok(config, "\n") :
349 strtok(config + 6 /* sizeof(struct sflap_hdr) */ + strlen("CONFIG:"), "\n");
350 do {
351 if (c == NULL)
352 break;
353 if (*c == 'g') {
354 strncpy(current, c + 2, sizeof(current));
355 add_group(gc, current);
356 how_many++;
357 } else if (*c == 'b' && !find_buddy(gc, c + 2)) {
358 char nm[80], sw[80], *tmp = c + 2;
359 int i = 0;
360 while (*tmp != ':' && *tmp)
361 nm[i++] = *tmp++;
362 if (*tmp == ':')
363 *tmp++ = '\0';
364 nm[i] = '\0';
365 i = 0;
366 while (*tmp)
367 sw[i++] = *tmp++;
368 sw[i] = '\0';
369 if (!find_buddy(gc, nm))
370 add_buddy(gc, current, nm, sw);
371 how_many++;
372
373 bud = g_list_append(bud, c + 2);
374 } else if (*c == 'p') {
375 GSList *d = gc->permit;
376 char *n;
377 name = g_malloc(strlen(c + 2) + 2);
378 g_snprintf(name, strlen(c + 2) + 1, "%s", c + 2);
379 n = g_strdup(normalize (name));
380 while (d) {
381 if (!g_strcasecmp(n, normalize (d->data)))
382 break;
383 d = d->next;
384 }
385 g_free(n);
386 if (!d)
387 gc->permit = g_slist_append(gc->permit, name);
388 else
389 g_free(name);
390 } else if (*c == 'd') {
391 GSList *d = gc->deny;
392 char *n;
393 name = g_malloc(strlen(c + 2) + 2);
394 g_snprintf(name, strlen(c + 2) + 1, "%s", c + 2);
395 n = g_strdup(normalize (name));
396 while (d) {
397 if (!g_strcasecmp(n, normalize (d->data)))
398 break;
399 d = d->next;
400 }
401 g_free(n);
402 if (!d)
403 gc->deny = g_slist_append(gc->deny, name);
404 else
405 g_free(name);
406 } else if (!strncmp("toc", c, 3)) {
407 sscanf(c + strlen(c) - 1, "%d", &gc->permdeny);
408 debug_printf("permdeny: %d\n", gc->permdeny);
409 if (gc->permdeny == 0)
410 gc->permdeny = 1;
411 } else if (*c == 'm') {
412 sscanf(c + 2, "%d", &gc->permdeny);
413 debug_printf("permdeny: %d\n", gc->permdeny);
414 if (gc->permdeny == 0)
415 gc->permdeny = 1;
416 }
417 } while ((c = strtok(NULL, "\n")));
418
419 if (bud != NULL) {
420 serv_add_buddies(gc, bud);
421 g_list_free(bud);
422 }
423 serv_set_permit_deny(gc);
424 }
425
426 /* perhaps the server dropped the buddy list, try importing from
427 cache */
428
429 if (how_many == 0 && !from_do_import) {
430 do_import(gc, NULL);
431 } else if (gc && (bud_list_cache_exists(gc) == FALSE)) {
432 do_export(gc);
433 }
434 }
435
436 void toc_build_config(struct gaim_connection *gc, char *s, int len, gboolean show)
437 {
438 GSList *grp = gc->groups;
439 GSList *mem;
440 struct group *g;
441 struct buddy *b;
442 GSList *plist = gc->permit;
443 GSList *dlist = gc->deny;
444
445 int pos = 0;
446
447 if (!gc->permdeny)
448 gc->permdeny = 1;
449
450 pos += g_snprintf(&s[pos], len - pos, "m %d\n", gc->permdeny);
451 while (len > pos && grp) {
452 g = (struct group *)grp->data;
453 pos += g_snprintf(&s[pos], len - pos, "g %s\n", g->name);
454 mem = g->members;
455 while (len > pos && mem) {
456 b = (struct buddy *)mem->data;
457 pos += g_snprintf(&s[pos], len - pos, "b %s%s%s\n", b->name,
458 (show && strcmp(b->name, b->show)) ? ":" : "",
459 (show && strcmp(b->name, b->show)) ? b->show : "");
460 mem = mem->next;
461 }
462 grp = g_slist_next(grp);
463 }
464
465 while (len > pos && plist) {
466 pos += g_snprintf(&s[pos], len - pos, "p %s\n", (char *)plist->data);
467 plist = plist->next;
468 }
469
470 while (len > pos && dlist) {
471 pos += g_snprintf(&s[pos], len - pos, "d %s\n", (char *)dlist->data);
472 dlist = dlist->next;
473 }
474 }
475
476 /* remove leading whitespace from a string */
477 static char *remove_spaces(char *str)
478 {
479 int i;
480 char *new;
481
482 if (str == NULL)
483 return NULL;
484
485 i = strspn(str, " \t\n\r\f");
486 new = &str[i];
487
488 return new;
489 }
490
491
492 /* translate an AIM 3 buddylist (*.lst) to a GAIM buddylist */
493 static void translate_lst(FILE *src_fp, char *dest)
494 {
495 char line[BUF_LEN], *line2;
496 char *name;
497 int i;
498
499 sprintf(dest, "m 1\n");
500
501 while (fgets(line, BUF_LEN, src_fp)) {
502 line2 = remove_spaces(line);
503 if (strstr(line2, "group") == line2) {
504 name = strpbrk(line2, " \t\n\r\f") + 1;
505 strcat(dest, "g ");
506 for (i = 0; i < strcspn(name, "\n\r"); i++)
507 if (name[i] != '\"')
508 strncat(dest, &name[i], 1);
509 strcat(dest, "\n");
510 }
511 if (strstr(line2, "buddy") == line2) {
512 name = strpbrk(line2, " \t\n\r\f") + 1;
513 strcat(dest, "b ");
514 for (i = 0; i < strcspn(name, "\n\r"); i++)
515 if (name[i] != '\"')
516 strncat(dest, &name[i], 1);
517 strcat(dest, "\n");
518 }
519 }
520
521 return;
522 }
523
524
525 /* translate an AIM 4 buddylist (*.blt) to GAIM format */
526 static void translate_blt(FILE *src_fp, char *dest)
527 {
528 int i;
529 char line[BUF_LEN];
530 char *buddy;
531
532 sprintf(dest, "m 1\n");
533
534 while (strstr(fgets(line, BUF_LEN, src_fp), "Buddy") == NULL);
535 while (strstr(fgets(line, BUF_LEN, src_fp), "list") == NULL);
536
537 while (1) {
538 fgets(line, BUF_LEN, src_fp);
539 if (strchr(line, '}') != NULL)
540 break;
541
542 /* Syntax starting with "<group> {" */
543 if (strchr(line, '{') != NULL) {
544 strcat(dest, "g ");
545 buddy = remove_spaces(strtok(line, "{"));
546 for (i = 0; i < strlen(buddy); i++) {
547 if (buddy[i] != '\"')
548 strncat(dest, &buddy[i], 1);
549 }
550 strcat(dest, "\n");
551 while (strchr(fgets(line, BUF_LEN, src_fp), '}') == NULL) {
552 buddy = remove_spaces(line);
553 strcat(dest, "b ");
554 if (strchr(buddy, '\"') != NULL) {
555 buddy++;
556 strncat(dest, buddy, strchr(buddy, '\"') - buddy);
557 strcat(dest, "\n");
558 } else
559 strcat(dest, buddy);
560 }
561 }
562 /* Syntax "group buddy buddy ..." */
563 else {
564 buddy = remove_spaces(strtok(line, " \n"));
565 strcat(dest, "g ");
566 if (strchr(buddy, '\"') != NULL) {
567 strcat(dest, &buddy[1]);
568 strcat(dest, " ");
569 buddy = remove_spaces(strtok(NULL, " \n"));
570 while (strchr(buddy, '\"') == NULL) {
571 strcat(dest, buddy);
572 strcat(dest, " ");
573 buddy = remove_spaces(strtok(NULL, " \n"));
574 }
575 strncat(dest, buddy, strlen(buddy) - 1);
576 } else {
577 strcat(dest, buddy);
578 }
579 strcat(dest, "\n");
580 while ((buddy = remove_spaces(strtok(NULL, " \n"))) != NULL) {
581 strcat(dest, "b ");
582 if (strchr(buddy, '\"') != NULL) {
583 strcat(dest, &buddy[1]);
584 strcat(dest, " ");
585 buddy = remove_spaces(strtok(NULL, " \n"));
586 while (strchr(buddy, '\"') == NULL) {
587 strcat(dest, buddy);
588 strcat(dest, " ");
589 buddy = remove_spaces(strtok(NULL, " \n"));
590 }
591 strncat(dest, buddy, strlen(buddy) - 1);
592 } else {
593 strcat(dest, buddy);
594 }
595 strcat(dest, "\n");
596 }
597 }
598 }
599
600 return;
601 }
602
603 static gchar *get_screenname_filename(const char *name)
604 {
605 gchar **split;
606 gchar *good;
607
608 split = g_strsplit(name, G_DIR_SEPARATOR_S, -1);
609 good = g_strjoinv(NULL, split);
610 g_strfreev(split);
611
612 g_strup(good);
613
614 return good;
615 }
616
617 /* see if a buddy list cache file for this user exists */
618
619 gboolean bud_list_cache_exists(struct gaim_connection *gc)
620 {
621 gboolean ret = FALSE;
622 char path[PATHSIZE];
623 char *file;
624 struct stat sbuf;
625 char *g_screenname;
626
627 g_screenname = get_screenname_filename(gc->username);
628
629 file = gaim_user_dir();
630 if (file != (char *)NULL) {
631 g_snprintf(path, sizeof path, "%s/%s.%d.blist", file, g_screenname,
632 (gc->protocol == PROTO_OSCAR) ? PROTO_TOC : gc->protocol);
633 if (!stat(path, &sbuf)) {
634 debug_printf("%s exists.\n", path);
635 ret = TRUE;
636 } else {
637 char path2[PATHSIZE];
638 debug_printf("%s does not exist.\n", path);
639 g_snprintf(path2, sizeof path2, "%s/%s.blist", file, g_screenname);
640 if (!stat(path2, &sbuf)) {
641 debug_printf("%s exists, moving to %s\n", path2, path);
642 if (rename(path2, path))
643 debug_printf("rename didn't work!\n");
644 else
645 ret = TRUE;
646 }
647 }
648 g_free(file);
649 }
650 g_free(g_screenname);
651 return ret;
652 }
653
654 void do_import(struct gaim_connection *gc, char *filename)
655 {
656 char *buf = g_malloc(BUF_LONG * 2);
657 char *buf2;
658 char *first = g_malloc(64);
659 char *file;
660 char path[PATHSIZE];
661 char *g_screenname;
662 int len;
663 FILE *f;
664
665 if (filename) {
666 g_snprintf(path, sizeof(path), "%s", filename);
667 } else {
668 g_screenname = get_screenname_filename(gc->username);
669
670 file = gaim_user_dir();
671 if (file != (char *)NULL) {
672 sprintf(path, "%s/%s.%d.blist", file, g_screenname,
673 (gc->protocol == PROTO_OSCAR) ? PROTO_TOC : gc->protocol);
674 g_free(file);
675 g_free(g_screenname);
676 } else {
677 g_free(g_screenname);
678 g_free(buf);
679 g_free(first);
680 return;
681 }
682 }
683
684 if (!(f = fopen(path, "r"))) {
685 debug_printf("Unable to open %s.\n", path);
686 g_free(buf);
687 g_free(first);
688 return;
689 }
690
691 fgets(first, 64, f);
692
693 /* AIM 4 buddy list */
694 if (!g_strncasecmp(first, "Config {", strlen("Config {"))) {
695 debug_printf("aim 4\n");
696 rewind(f);
697 translate_blt(f, buf);
698 debug_printf("%s\n", buf);
699 buf2 = buf;
700 buf = g_malloc(8193);
701 g_snprintf(buf, 8192, "toc_set_config {%s}\n", buf2);
702 g_free(buf2);
703 /* AIM 3 buddy list */
704 } else if (strstr(first, "group") != NULL) {
705 debug_printf("aim 3\n");
706 rewind(f);
707 translate_lst(f, buf);
708 debug_printf("%s\n", buf);
709 buf2 = buf;
710 buf = g_malloc(8193);
711 g_snprintf(buf, 8192, "toc_set_config {%s}\n", buf2);
712 g_free(buf2);
713 /* GAIM buddy list - no translation */
714 } else if (first[0] == 'm') {
715 rewind(f);
716 len = fread(buf, 1, BUF_LONG * 2, f);
717 buf[len] = '\0';
718 buf2 = buf;
719 buf = g_malloc(8193);
720 g_snprintf(buf, 8192, "toc_set_config {%s}\n", buf2);
721 g_free(buf2);
722 /* Something else */
723 } else {
724 g_free(buf);
725 g_free(first);
726 fclose(f);
727 return;
728 }
729
730 parse_toc_buddy_list(gc, buf, 1);
731
732 fclose(f);
733
734 g_free(buf);
735 g_free(first);
736 }
737
738 void do_export(struct gaim_connection *g)
739 {
740 FILE *dir;
741 FILE *f;
742 char buf[32 * 1024];
743 char *file;
744 char path[PATHSIZE];
745 char *g_screenname;
746
747 file = gaim_user_dir();
748 if (!file)
749 return;
750
751 strcpy(buf, file);
752 dir = fopen(buf, "r");
753 if (!dir)
754 mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR);
755 else
756 fclose(dir);
757
758 g_screenname = get_screenname_filename(g->username);
759
760 sprintf(path, "%s/%s.%d.blist", file, g_screenname,
761 (g->protocol == PROTO_OSCAR) ? PROTO_TOC : g->protocol);
762 if ((f = fopen(path, "w"))) {
763 debug_printf("writing %s\n", path);
764 toc_build_config(g, buf, 8192 - 1, TRUE);
765 fprintf(f, "%s\n", buf);
766 fclose(f);
767 chmod(buf, S_IRUSR | S_IWUSR);
768 } else {
769 debug_printf("unable to write %s\n", path);
770 }
771
772 g_free(g_screenname);
773 g_free(file);
774 }