4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
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.
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.
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
26 #include <sys/types.h>
34 void remove_buddy(struct gaim_connection
*gc
, struct group
*rem_g
, struct buddy
*rem_b
)
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
47 grp
= g_slist_find(gc
->groups
, rem_g
);
48 delg
= (struct group
*)grp
->data
;
51 mem
= g_slist_find(mem
, rem_b
);
52 delb
= (struct buddy
*)mem
->data
;
54 delg
->members
= g_slist_remove(delg
->members
, delb
);
56 ui_remove_buddy(gc
, rem_g
, rem_b
);
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 */
64 void remove_group(struct gaim_connection
*gc
, struct group
*rem_g
)
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 */
76 grp
= g_slist_find(gc
->groups
, rem_g
);
77 delg
= (struct group
*)grp
->data
;
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 */
87 gc
->groups
= g_slist_remove(gc
->groups
, delg
);
89 serv_remove_buddies(gc
, tmp
, rem_g
->name
);
92 tmp
= g_list_remove(tmp
, tmp
->data
);
95 ui_remove_group(gc
, rem_g
);
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. */
103 struct buddy
*add_buddy(struct gaim_connection
*gc
, char *group
, char *buddy
, char *show
)
109 if (!g_slist_find(connections
, gc
))
112 if ((b
= find_buddy(gc
, buddy
)) != NULL
)
115 g
= find_group(gc
, group
);
118 g
= add_group(gc
, group
);
120 b
= (struct buddy
*)g_new0(struct buddy
, 1);
128 if (gc
->prpl
->normalize
)
129 good
= gc
->prpl
->normalize(buddy
);
133 g_snprintf(b
->name
, sizeof(b
->name
), "%s", good
);
134 g_snprintf(b
->show
, sizeof(b
->show
), "%s", show
? (show
[0] ? show
: good
) : good
);
136 g
->members
= g_slist_append(g
->members
, b
);
141 ui_add_buddy(gc
, g
, b
);
146 struct group
*add_group(struct gaim_connection
*gc
, char *group
)
148 struct group
*g
= find_group(gc
, group
);
151 if (!g_slist_find(connections
, gc
))
153 g
= (struct group
*)g_new0(struct group
, 1);
158 strncpy(g
->name
, group
, sizeof(g
->name
));
159 gc
->groups
= g_slist_append(gc
->groups
, g
);
168 struct group
*find_group(struct gaim_connection
*gc
, char *group
)
172 GSList
*c
= connections
;
173 struct gaim_connection
*z
;
174 char *grpname
= g_malloc(strlen(group
) + 1);
176 strcpy(grpname
, normalize (group
));
178 if (!g_slist_find(connections
, gc
))
182 g
= (struct group
*)grp
->data
;
183 if (!g_strcasecmp(normalize (g
->name
), grpname
)) {
187 grp
= g_slist_next(grp
);
194 z
= (struct gaim_connection
*)c
->data
;
197 g
= (struct group
*)grp
->data
;
198 if (!g_strcasecmp(normalize (g
->name
), grpname
)) {
202 grp
= g_slist_next(grp
);
212 struct group
*find_group_by_buddy(struct gaim_connection
*gc
, char *who
)
219 char *(*norm
)(const char *);
222 if (gc
->prpl
->normalize
)
223 norm
= gc
->prpl
->normalize
;
226 whoname
= g_strdup(norm(who
));
229 g
= (struct group
*)grp
->data
;
233 b
= (struct buddy
*)mem
->data
;
234 if (!strcmp(norm(b
->name
), whoname
)) {
240 grp
= g_slist_next(grp
);
245 GSList
*c
= connections
;
246 struct gaim_connection
*z
;
248 z
= (struct gaim_connection
*)c
->data
;
249 if (z
->prpl
->normalize
)
250 norm
= z
->prpl
->normalize
;
253 whoname
= g_strdup(norm(who
));
256 g
= (struct group
*)grp
->data
;
260 b
= (struct buddy
*)mem
->data
;
261 if (!strcmp(norm(b
->name
), whoname
)) {
267 grp
= g_slist_next(grp
);
276 struct buddy
*find_buddy(struct gaim_connection
*gc
, char *who
)
282 struct gaim_connection
*z
;
285 char *(*norm
)(const char *);
288 if (!g_slist_find(connections
, gc
))
290 if (gc
->prpl
->normalize
)
291 norm
= gc
->prpl
->normalize
;
294 whoname
= g_strdup(norm(who
));
297 g
= (struct group
*)grp
->data
;
301 b
= (struct buddy
*)mem
->data
;
302 if (!strcmp(norm(b
->name
), whoname
)) {
308 grp
= g_slist_next(grp
);
315 z
= (struct gaim_connection
*)c
->data
;
316 if (z
->prpl
->normalize
)
317 norm
= z
->prpl
->normalize
;
320 whoname
= g_strdup(norm(who
));
323 g
= (struct group
*)grp
->data
;
327 b
= (struct buddy
*)mem
->data
;
328 if (!strcmp(norm(b
->name
), whoname
)) {
334 grp
= g_slist_next(grp
);
343 void parse_toc_buddy_list(struct gaim_connection
*gc
, char *config
)
353 if (config
!= NULL
) {
355 /* skip "CONFIG:" (if it exists) */
356 c
= strncmp(config
+ 6 /* sizeof(struct sflap_hdr) */ , "CONFIG:", strlen("CONFIG:")) ?
357 strtok(config
, "\n") :
358 strtok(config
+ 6 /* sizeof(struct sflap_hdr) */ + strlen("CONFIG:"), "\n");
363 strncpy(current
, c
+ 2, sizeof(current
));
364 if (!find_group(gc
, current
)) {
365 add_group(gc
, current
);
368 } else if (*c
== 'b' && !find_buddy(gc
, c
+ 2)) {
369 char nm
[80], sw
[388], *tmp
= c
+ 2;
371 while (*tmp
!= ':' && *tmp
)
380 if (!find_buddy(gc
, nm
)) {
381 add_buddy(gc
, current
, nm
, sw
);
383 bud
= g_list_append(bud
, c
+ 2);
385 } else if (*c
== 'p') {
386 GSList
*d
= gc
->permit
;
388 name
= g_malloc(strlen(c
+ 2) + 2);
389 g_snprintf(name
, strlen(c
+ 2) + 1, "%s", c
+ 2);
390 n
= g_strdup(normalize (name
));
392 if (!g_strcasecmp(n
, normalize (d
->data
)))
398 gc
->permit
= g_slist_append(gc
->permit
, name
);
402 } else if (*c
== 'd') {
403 GSList
*d
= gc
->deny
;
405 name
= g_malloc(strlen(c
+ 2) + 2);
406 g_snprintf(name
, strlen(c
+ 2) + 1, "%s", c
+ 2);
407 n
= g_strdup(normalize (name
));
409 if (!g_strcasecmp(n
, normalize (d
->data
)))
415 gc
->deny
= g_slist_append(gc
->deny
, name
);
419 } else if (!strncmp("toc", c
, 3)) {
420 sscanf(c
+ strlen(c
) - 1, "%d", &gc
->permdeny
);
421 debug_printf("permdeny: %d\n", gc
->permdeny
);
422 if (gc
->permdeny
== 0)
424 } else if (*c
== 'm') {
425 sscanf(c
+ 2, "%d", &gc
->permdeny
);
426 debug_printf("permdeny: %d\n", gc
->permdeny
);
427 if (gc
->permdeny
== 0)
430 } while ((c
= strtok(NULL
, "\n")));
433 serv_add_buddies(gc
, bud
);
436 serv_set_permit_deny(gc
);
443 void toc_build_config(struct gaim_connection
*gc
, char *s
, int len
, gboolean show
)
445 GSList
*grp
= gc
->groups
;
449 GSList
*plist
= gc
->permit
;
450 GSList
*dlist
= gc
->deny
;
457 pos
+= g_snprintf(&s
[pos
], len
- pos
, "m %d\n", gc
->permdeny
);
458 while (len
> pos
&& grp
) {
459 g
= (struct group
*)grp
->data
;
460 pos
+= g_snprintf(&s
[pos
], len
- pos
, "g %s\n", g
->name
);
462 while (len
> pos
&& mem
) {
463 b
= (struct buddy
*)mem
->data
;
464 pos
+= g_snprintf(&s
[pos
], len
- pos
, "b %s%s%s\n", b
->name
,
465 (show
&& strcmp(b
->name
, b
->show
)) ? ":" : "",
466 (show
&& strcmp(b
->name
, b
->show
)) ? b
->show
: "");
469 grp
= g_slist_next(grp
);
472 while (len
> pos
&& plist
) {
473 pos
+= g_snprintf(&s
[pos
], len
- pos
, "p %s\n", (char *)plist
->data
);
477 while (len
> pos
&& dlist
) {
478 pos
+= g_snprintf(&s
[pos
], len
- pos
, "d %s\n", (char *)dlist
->data
);
483 /* translate an AIM 3 buddylist (*.lst) to a Gaim buddylist */
484 static GString
*translate_lst(FILE *src_fp
)
486 char line
[BUF_LEN
], *line2
;
490 GString
*dest
= g_string_new("m 1\n");
492 while (fgets(line
, BUF_LEN
, src_fp
)) {
493 line2
= g_strchug(line
);
494 if (strstr(line2
, "group") == line2
) {
495 name
= strpbrk(line2
, " \t\n\r\f") + 1;
496 dest
= g_string_append(dest
, "g ");
497 for (i
= 0; i
< strcspn(name
, "\n\r"); i
++)
499 dest
= g_string_append_c(dest
, name
[i
]);
500 dest
= g_string_append_c(dest
, '\n');
502 if (strstr(line2
, "buddy") == line2
) {
503 name
= strpbrk(line2
, " \t\n\r\f") + 1;
504 dest
= g_string_append(dest
, "b ");
505 for (i
= 0; i
< strcspn(name
, "\n\r"); i
++)
507 dest
= g_string_append_c(dest
, name
[i
]);
508 dest
= g_string_append_c(dest
, '\n');
516 /* translate an AIM 4 buddylist (*.blt) to Gaim format */
517 static GString
*translate_blt(FILE *src_fp
)
523 GString
*dest
= g_string_new("m 1\n");
525 while (strstr(fgets(line
, BUF_LEN
, src_fp
), "Buddy") == NULL
);
526 while (strstr(fgets(line
, BUF_LEN
, src_fp
), "list") == NULL
);
529 fgets(line
, BUF_LEN
, src_fp
); g_strchomp(line
);
530 if (strchr(line
, '}') != NULL
)
533 if (strchr(line
, '{') != NULL
) {
534 /* Syntax starting with "<group> {" */
536 dest
= g_string_append(dest
, "g ");
537 buddy
= g_strchug(strtok(line
, "{"));
538 for (i
= 0; i
< strlen(buddy
); i
++)
539 if (buddy
[i
] != '\"')
540 dest
= g_string_append_c(dest
, buddy
[i
]);
541 dest
= g_string_append_c(dest
, '\n');
542 while (strchr(fgets(line
, BUF_LEN
, src_fp
), '}') == NULL
) {
543 gboolean pounce
= FALSE
;
546 buddy
= g_strchug(line
);
547 debug_printf("\nbuddy: \"%s\"\n\n", buddy
);
548 dest
= g_string_append(dest
, "b ");
549 if (strchr(buddy
, '{') != NULL
) {
550 /* buddy pounce, etc */
551 char *pos
= strchr(buddy
, '{') - 1;
555 if ((e
= strchr(buddy
, '\"')) != NULL
) {
559 dest
= g_string_append(dest
, buddy
);
560 dest
= g_string_append_c(dest
, '\n');
563 fgets(line
, BUF_LEN
, src_fp
);
564 while (!strchr(line
, '}'));
568 /* Syntax "group buddy buddy ..." */
569 buddy
= g_strchug(strtok(line
, " \n"));
570 dest
= g_string_append(dest
, "g ");
571 if (strchr(buddy
, '\"') != NULL
) {
572 dest
= g_string_append(dest
, &buddy
[1]);
573 dest
= g_string_append_c(dest
, ' ');
574 buddy
= g_strchug(strtok(NULL
, " \n"));
575 while (strchr(buddy
, '\"') == NULL
) {
576 dest
= g_string_append(dest
, buddy
);
577 dest
= g_string_append_c(dest
, ' ');
578 buddy
= g_strchug(strtok(NULL
, " \n"));
580 buddy
[strlen(buddy
) - 1] = '\0';
581 dest
= g_string_append(dest
, buddy
);
583 dest
= g_string_append(dest
, buddy
);
585 dest
= g_string_append_c(dest
, '\n');
586 while ((buddy
= g_strchug(strtok(NULL
, " \n"))) != NULL
) {
587 dest
= g_string_append(dest
, "b ");
588 if (strchr(buddy
, '\"') != NULL
) {
589 dest
= g_string_append(dest
, &buddy
[1]);
590 dest
= g_string_append_c(dest
, ' ');
591 buddy
= g_strchug(strtok(NULL
, " \n"));
592 while (strchr(buddy
, '\"') == NULL
) {
593 dest
= g_string_append(dest
, buddy
);
594 dest
= g_string_append_c(dest
, ' ');
595 buddy
= g_strchug(strtok(NULL
, " \n"));
597 buddy
[strlen(buddy
) - 1] = '\0';
598 dest
= g_string_append(dest
, buddy
);
600 dest
= g_string_append(dest
, buddy
);
602 dest
= g_string_append_c(dest
, '\n');
610 static GString
*translate_gnomeicu(FILE *src_fp
)
613 GString
*dest
= g_string_new("m 1\ng Buddies\n");
615 while (strstr(fgets(line
, BUF_LEN
, src_fp
), "NewContacts") == NULL
);
617 while (fgets(line
, BUF_LEN
, src_fp
)) {
620 if (line
[0] == '\n' || line
[0] == '[')
622 eq
= strchr(line
, '=');
626 eq
= strchr(eq
, ',');
629 dest
= g_string_append(dest
, "b ");
630 dest
= g_string_append(dest
, line
);
631 dest
= g_string_append_c(dest
, '\n');
637 static gchar
*get_screenname_filename(const char *name
)
642 split
= g_strsplit(name
, G_DIR_SEPARATOR_S
, -1);
643 good
= g_strjoinv(NULL
, split
);
651 /* see if a buddy list cache file for this user exists */
653 gboolean
bud_list_cache_exists(struct gaim_connection
*gc
)
655 gboolean ret
= FALSE
;
661 g_screenname
= get_screenname_filename(gc
->username
);
663 file
= gaim_user_dir();
664 if (file
!= (char *)NULL
) {
665 g_snprintf(path
, sizeof path
, "%s/%s.%d.blist", file
, g_screenname
, gc
->protocol
);
666 if (!stat(path
, &sbuf
)) {
667 debug_printf("%s exists.\n", path
);
670 char path2
[PATHSIZE
];
671 debug_printf("%s does not exist.\n", path
);
672 g_snprintf(path2
, sizeof path2
, "%s/%s.blist", file
, g_screenname
);
673 if (!stat(path2
, &sbuf
)) {
674 debug_printf("%s exists, moving to %s\n", path2
, path
);
675 if (rename(path2
, path
))
676 debug_printf("rename didn't work!\n");
683 g_free(g_screenname
);
687 void do_import(struct gaim_connection
*gc
, char *filename
)
697 g_snprintf(path
, sizeof(path
), "%s", filename
);
699 char *g_screenname
= get_screenname_filename(gc
->username
);
700 char *file
= gaim_user_dir();
702 if (file
!= (char *)NULL
) {
703 sprintf(path
, "%s/%s.%d.blist", file
, g_screenname
, gc
->protocol
);
705 g_free(g_screenname
);
707 g_free(g_screenname
);
712 if (stat(path
, &st
)) {
713 debug_printf("Unable to stat %s.\n", path
);
717 if (!(f
= fopen(path
, "r"))) {
718 debug_printf("Unable to open %s.\n", path
);
724 if ((first
[0] == '\n') || (first
[0] == '\r' && first
[1] == '\n'))
727 if (!g_strncasecmp(first
, "Config {", strlen("Config {"))) {
728 /* AIM 4 buddy list */
729 debug_printf("aim 4\n");
731 buf
= translate_blt(f
);
732 } else if (strstr(first
, "group") != NULL
) {
733 /* AIM 3 buddy list */
734 debug_printf("aim 3\n");
736 buf
= translate_lst(f
);
737 } else if (!g_strncasecmp(first
, "[User]", strlen("[User]"))) {
738 /* GnomeICU (hopefully) */
739 debug_printf("gnomeicu\n");
741 buf
= translate_gnomeicu(f
);
742 } else if (first
[0] == 'm') {
743 /* Gaim buddy list - no translation */
744 char buf2
[BUF_LONG
* 2];
745 buf
= g_string_new("");
748 len
= fread(buf2
, 1, BUF_LONG
* 2 - 1, f
);
752 buf
= g_string_append(buf
, buf2
);
753 if (len
!= BUF_LONG
* 2 - 1)
761 buf
= g_string_prepend(buf
, "toc_set_config {");
762 buf
= g_string_append(buf
, "}\n");
763 parse_toc_buddy_list(gc
, buf
->str
);
764 g_string_free(buf
, TRUE
);
768 void do_export(struct gaim_connection
*g
)
777 file
= gaim_user_dir();
782 dir
= fopen(buf
, "r");
784 mkdir(buf
, S_IRUSR
| S_IWUSR
| S_IXUSR
);
788 g_screenname
= get_screenname_filename(g
->username
);
790 sprintf(path
, "%s/%s.%d.blist", file
, g_screenname
, g
->protocol
);
791 if ((f
= fopen(path
, "w"))) {
792 debug_printf("writing %s\n", path
);
793 toc_build_config(g
, buf
, 8192 - 1, TRUE
);
794 fprintf(f
, "%s\n", buf
);
796 chmod(buf
, S_IRUSR
| S_IWUSR
);
798 debug_printf("unable to write %s\n", path
);
801 g_free(g_screenname
);
805 static gboolean
is_blocked(struct buddy
*b
)
807 struct gaim_connection
*gc
= b
->gc
;
809 if (gc
->permdeny
== PERMIT_ALL
)
812 if (gc
->permdeny
== PERMIT_NONE
) {
813 if (g_strcasecmp(b
->name
, gc
->displayname
))
819 if (gc
->permdeny
== PERMIT_SOME
) {
820 char *x
= g_strdup(normalize(b
->name
));
821 GSList
*s
= gc
->permit
;
823 if (!g_strcasecmp(x
, normalize(s
->data
)))
833 if (gc
->permdeny
== DENY_SOME
) {
834 char *x
= g_strdup(normalize(b
->name
));
835 GSList
*s
= gc
->deny
;
837 if (!g_strcasecmp(x
, normalize(s
->data
)))
850 void signoff_blocked(struct gaim_connection
*gc
)
852 GSList
*g
= gc
->groups
;
854 GSList
*m
= ((struct group
*)g
->data
)->members
;
856 struct buddy
*b
= m
->data
;
858 serv_got_update(gc
, b
->name
, 0, 0, 0, 0, 0, 0);