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>
42 void remove_buddy(struct gaim_connection
*gc
, struct group
*rem_g
, struct buddy
*rem_b
)
50 /* we assume that gc is not NULL and that the buddy exists somewhere within the
51 * gc's buddy list, therefore we can safely remove it. we need to ensure this
55 grp
= g_slist_find(gc
->groups
, rem_g
);
56 delg
= (struct group
*)grp
->data
;
59 mem
= g_slist_find(mem
, rem_b
);
60 delb
= (struct buddy
*)mem
->data
;
62 delg
->members
= g_slist_remove(delg
->members
, delb
);
64 ui_remove_buddy(gc
, rem_g
, rem_b
);
68 /* we don't flush buddy list to cache because in the case of remove_group that would
69 * mean writing to the buddy list file once for each buddy, plus one more time */
72 void remove_group(struct gaim_connection
*gc
, struct group
*rem_g
)
81 /* we assume that the group actually does exist within the gc, and that the gc is not NULL.
82 * the UI is responsible for this */
84 grp
= g_slist_find(gc
->groups
, rem_g
);
85 delg
= (struct group
*)grp
->data
;
88 while (delg
->members
) {
89 delb
= (struct buddy
*)delg
->members
->data
;
90 tmp
= g_list_append(tmp
, g_strdup(delb
->name
));
91 remove_buddy(gc
, delg
, delb
); /* this should take care of removing
92 the group_show if necessary */
95 gc
->groups
= g_slist_remove(gc
->groups
, delg
);
97 serv_remove_buddies(gc
, tmp
, rem_g
->name
);
100 tmp
= g_list_remove(tmp
, tmp
->data
);
103 ui_remove_group(gc
, rem_g
);
107 /* don't flush buddy list to cache in order to be consistent with remove_buddy,
108 * mostly. remove_group is only called from one place, so we'll let it handle it. */
111 struct buddy
*add_buddy(struct gaim_connection
*gc
, const char *group
, const char *buddy
, const char *show
)
117 if (!g_slist_find(connections
, gc
))
120 if ((b
= find_buddy(gc
, buddy
)) != NULL
)
123 g
= find_group(gc
, group
);
126 g
= add_group(gc
, group
);
128 b
= (struct buddy
*)g_new0(struct buddy
, 1);
136 if (gc
->prpl
->normalize
)
137 good
= gc
->prpl
->normalize(buddy
);
141 g_snprintf(b
->name
, sizeof(b
->name
), "%s", good
);
142 g_snprintf(b
->show
, sizeof(b
->show
), "%s", show
? (show
[0] ? show
: good
) : good
);
144 g
->members
= g_slist_append(g
->members
, b
);
149 ui_add_buddy(gc
, g
, b
);
154 struct group
*add_group(struct gaim_connection
*gc
, const char *group
)
156 struct group
*g
= find_group(gc
, group
);
159 if (!g_slist_find(connections
, gc
))
161 g
= (struct group
*)g_new0(struct group
, 1);
166 strncpy(g
->name
, group
, sizeof(g
->name
));
167 gc
->groups
= g_slist_append(gc
->groups
, g
);
176 struct group
*find_group(struct gaim_connection
*gc
, const char *group
)
180 GSList
*c
= connections
;
181 struct gaim_connection
*z
;
182 char *grpname
= g_malloc(strlen(group
) + 1);
184 strcpy(grpname
, normalize (group
));
186 if (!g_slist_find(connections
, gc
))
190 g
= (struct group
*)grp
->data
;
191 if (!g_strcasecmp(normalize (g
->name
), grpname
)) {
195 grp
= g_slist_next(grp
);
202 z
= (struct gaim_connection
*)c
->data
;
205 g
= (struct group
*)grp
->data
;
206 if (!g_strcasecmp(normalize (g
->name
), grpname
)) {
210 grp
= g_slist_next(grp
);
220 struct group
*find_group_by_buddy(struct gaim_connection
*gc
, const char *who
)
227 char *(*norm
)(const char *);
230 if (gc
->prpl
->normalize
)
231 norm
= gc
->prpl
->normalize
;
234 whoname
= g_strdup(norm(who
));
237 g
= (struct group
*)grp
->data
;
241 b
= (struct buddy
*)mem
->data
;
242 if (!strcmp(norm(b
->name
), whoname
)) {
248 grp
= g_slist_next(grp
);
253 GSList
*c
= connections
;
254 struct gaim_connection
*z
;
256 z
= (struct gaim_connection
*)c
->data
;
257 if (z
->prpl
->normalize
)
258 norm
= z
->prpl
->normalize
;
261 whoname
= g_strdup(norm(who
));
264 g
= (struct group
*)grp
->data
;
268 b
= (struct buddy
*)mem
->data
;
269 if (!strcmp(norm(b
->name
), whoname
)) {
275 grp
= g_slist_next(grp
);
284 struct buddy
*find_buddy(struct gaim_connection
*gc
, const char *who
)
290 struct gaim_connection
*z
;
293 char *(*norm
)(const char *);
296 if (!g_slist_find(connections
, gc
))
298 if (gc
->prpl
->normalize
)
299 norm
= gc
->prpl
->normalize
;
302 whoname
= g_strdup(norm(who
));
305 g
= (struct group
*)grp
->data
;
309 b
= (struct buddy
*)mem
->data
;
310 if (!strcmp(norm(b
->name
), whoname
)) {
316 grp
= g_slist_next(grp
);
323 z
= (struct gaim_connection
*)c
->data
;
324 if (z
->prpl
->normalize
)
325 norm
= z
->prpl
->normalize
;
328 whoname
= g_strdup(norm(who
));
331 g
= (struct group
*)grp
->data
;
335 b
= (struct buddy
*)mem
->data
;
336 if (!strcmp(norm(b
->name
), whoname
)) {
342 grp
= g_slist_next(grp
);
351 void parse_toc_buddy_list(struct gaim_connection
*gc
, char *config
)
361 if (config
!= NULL
) {
363 /* skip "CONFIG:" (if it exists) */
364 c
= strncmp(config
+ 6 /* sizeof(struct sflap_hdr) */ , "CONFIG:", strlen("CONFIG:")) ?
365 strtok(config
, "\n") :
366 strtok(config
+ 6 /* sizeof(struct sflap_hdr) */ + strlen("CONFIG:"), "\n");
371 strncpy(current
, c
+ 2, sizeof(current
));
372 if (!find_group(gc
, current
)) {
373 add_group(gc
, current
);
376 } else if (*c
== 'b' && !find_buddy(gc
, c
+ 2)) {
377 char nm
[80], sw
[BUDDY_ALIAS_MAXLEN
], *tmp
= c
+ 2;
379 while (*tmp
!= ':' && *tmp
&& i
< sizeof(nm
) - 1)
382 while (*tmp
!= ':' && *tmp
)
390 while (*tmp
&& i
< sizeof(sw
) - 1)
393 if (!find_buddy(gc
, nm
)) {
394 add_buddy(gc
, current
, nm
, sw
);
396 bud
= g_list_append(bud
, c
+ 2);
398 } else if (*c
== 'p') {
399 GSList
*d
= gc
->permit
;
401 name
= g_malloc(strlen(c
+ 2) + 2);
402 g_snprintf(name
, strlen(c
+ 2) + 1, "%s", c
+ 2);
403 n
= g_strdup(normalize (name
));
405 if (!g_strcasecmp(n
, normalize (d
->data
)))
411 gc
->permit
= g_slist_append(gc
->permit
, name
);
415 } else if (*c
== 'd') {
416 GSList
*d
= gc
->deny
;
418 name
= g_malloc(strlen(c
+ 2) + 2);
419 g_snprintf(name
, strlen(c
+ 2) + 1, "%s", c
+ 2);
420 n
= g_strdup(normalize (name
));
422 if (!g_strcasecmp(n
, normalize (d
->data
)))
428 gc
->deny
= g_slist_append(gc
->deny
, name
);
432 } else if (!strncmp("toc", c
, 3)) {
433 sscanf(c
+ strlen(c
) - 1, "%d", &gc
->permdeny
);
434 debug_printf("permdeny: %d\n", gc
->permdeny
);
435 if (gc
->permdeny
== 0)
437 } else if (*c
== 'm') {
438 sscanf(c
+ 2, "%d", &gc
->permdeny
);
439 debug_printf("permdeny: %d\n", gc
->permdeny
);
440 if (gc
->permdeny
== 0)
443 } while ((c
= strtok(NULL
, "\n")));
446 serv_add_buddies(gc
, bud
);
449 serv_set_permit_deny(gc
);
457 void toc_build_config(struct gaim_connection
*gc
, char *s
, int len
, gboolean show
)
459 GSList
*grp
= gc
->groups
;
463 GSList
*plist
= gc
->permit
;
464 GSList
*dlist
= gc
->deny
;
471 pos
+= g_snprintf(&s
[pos
], len
- pos
, "m %d\n", gc
->permdeny
);
472 while (len
> pos
&& grp
) {
473 g
= (struct group
*)grp
->data
;
474 pos
+= g_snprintf(&s
[pos
], len
- pos
, "g %s\n", g
->name
);
476 while (len
> pos
&& mem
) {
477 b
= (struct buddy
*)mem
->data
;
478 pos
+= g_snprintf(&s
[pos
], len
- pos
, "b %s%s%s\n", b
->name
,
479 (show
&& strcmp(b
->name
, b
->show
)) ? ":" : "",
480 (show
&& strcmp(b
->name
, b
->show
)) ? b
->show
: "");
483 grp
= g_slist_next(grp
);
486 while (len
> pos
&& plist
) {
487 pos
+= g_snprintf(&s
[pos
], len
- pos
, "p %s\n", (char *)plist
->data
);
491 while (len
> pos
&& dlist
) {
492 pos
+= g_snprintf(&s
[pos
], len
- pos
, "d %s\n", (char *)dlist
->data
);
497 /* translate an AIM 3 buddylist (*.lst) to a Gaim buddylist */
498 static GString
*translate_lst(FILE *src_fp
)
500 char line
[BUF_LEN
], *line2
;
504 GString
*dest
= g_string_new("m 1\n");
506 while (fgets(line
, BUF_LEN
, src_fp
)) {
507 line2
= g_strchug(line
);
508 if (strstr(line2
, "group") == line2
) {
509 name
= strpbrk(line2
, " \t\n\r\f") + 1;
510 dest
= g_string_append(dest
, "g ");
511 for (i
= 0; i
< strcspn(name
, "\n\r"); i
++)
513 dest
= g_string_append_c(dest
, name
[i
]);
514 dest
= g_string_append_c(dest
, '\n');
516 if (strstr(line2
, "buddy") == line2
) {
517 name
= strpbrk(line2
, " \t\n\r\f") + 1;
518 dest
= g_string_append(dest
, "b ");
519 for (i
= 0; i
< strcspn(name
, "\n\r"); i
++)
521 dest
= g_string_append_c(dest
, name
[i
]);
522 dest
= g_string_append_c(dest
, '\n');
530 /* translate an AIM 4 buddylist (*.blt) to Gaim format */
531 static GString
*translate_blt(FILE *src_fp
)
537 GString
*dest
= g_string_new("m 1\n");
539 while (strstr(fgets(line
, BUF_LEN
, src_fp
), "Buddy") == NULL
);
540 while (strstr(fgets(line
, BUF_LEN
, src_fp
), "list") == NULL
);
543 fgets(line
, BUF_LEN
, src_fp
); g_strchomp(line
);
544 if (strchr(line
, '}') != NULL
)
547 if (strchr(line
, '{') != NULL
) {
548 /* Syntax starting with "<group> {" */
550 dest
= g_string_append(dest
, "g ");
551 buddy
= g_strchug(strtok(line
, "{"));
552 for (i
= 0; i
< strlen(buddy
); i
++)
553 if (buddy
[i
] != '\"')
554 dest
= g_string_append_c(dest
, buddy
[i
]);
555 dest
= g_string_append_c(dest
, '\n');
556 while (strchr(fgets(line
, BUF_LEN
, src_fp
), '}') == NULL
) {
557 gboolean pounce
= FALSE
;
560 buddy
= g_strchug(line
);
561 debug_printf("\nbuddy: \"%s\"\n\n", buddy
);
562 dest
= g_string_append(dest
, "b ");
563 if (strchr(buddy
, '{') != NULL
) {
564 /* buddy pounce, etc */
565 char *pos
= strchr(buddy
, '{') - 1;
569 if ((e
= strchr(buddy
, '\"')) != NULL
) {
573 dest
= g_string_append(dest
, buddy
);
574 dest
= g_string_append_c(dest
, '\n');
577 fgets(line
, BUF_LEN
, src_fp
);
578 while (!strchr(line
, '}'));
582 /* Syntax "group buddy buddy ..." */
583 buddy
= g_strchug(strtok(line
, " \n"));
584 dest
= g_string_append(dest
, "g ");
585 if (strchr(buddy
, '\"') != NULL
) {
586 dest
= g_string_append(dest
, &buddy
[1]);
587 dest
= g_string_append_c(dest
, ' ');
588 buddy
= g_strchug(strtok(NULL
, " \n"));
589 while (strchr(buddy
, '\"') == NULL
) {
590 dest
= g_string_append(dest
, buddy
);
591 dest
= g_string_append_c(dest
, ' ');
592 buddy
= g_strchug(strtok(NULL
, " \n"));
594 buddy
[strlen(buddy
) - 1] = '\0';
595 dest
= g_string_append(dest
, buddy
);
597 dest
= g_string_append(dest
, buddy
);
599 dest
= g_string_append_c(dest
, '\n');
600 while ((buddy
= g_strchug(strtok(NULL
, " \n"))) != NULL
) {
601 dest
= g_string_append(dest
, "b ");
602 if (strchr(buddy
, '\"') != NULL
) {
603 dest
= g_string_append(dest
, &buddy
[1]);
604 dest
= g_string_append_c(dest
, ' ');
605 buddy
= g_strchug(strtok(NULL
, " \n"));
606 while (strchr(buddy
, '\"') == NULL
) {
607 dest
= g_string_append(dest
, buddy
);
608 dest
= g_string_append_c(dest
, ' ');
609 buddy
= g_strchug(strtok(NULL
, " \n"));
611 buddy
[strlen(buddy
) - 1] = '\0';
612 dest
= g_string_append(dest
, buddy
);
614 dest
= g_string_append(dest
, buddy
);
616 dest
= g_string_append_c(dest
, '\n');
624 static GString
*translate_gnomeicu(FILE *src_fp
)
627 GString
*dest
= g_string_new("m 1\ng Buddies\n");
629 while (strstr(fgets(line
, BUF_LEN
, src_fp
), "NewContacts") == NULL
);
631 while (fgets(line
, BUF_LEN
, src_fp
)) {
634 if (line
[0] == '\n' || line
[0] == '[')
636 eq
= strchr(line
, '=');
640 eq
= strchr(eq
, ',');
643 dest
= g_string_append(dest
, "b ");
644 dest
= g_string_append(dest
, line
);
645 dest
= g_string_append_c(dest
, '\n');
651 static gchar
*get_screenname_filename(const char *name
)
656 split
= g_strsplit(name
, G_DIR_SEPARATOR_S
, -1);
657 good
= g_strjoinv(NULL
, split
);
665 /* see if a buddy list cache file for this user exists */
667 gboolean
bud_list_cache_exists(struct gaim_connection
*gc
)
669 gboolean ret
= FALSE
;
675 g_screenname
= get_screenname_filename(gc
->username
);
677 file
= gaim_user_dir();
678 if (file
!= (char *)NULL
) {
679 g_snprintf(path
, sizeof path
, "%s" G_DIR_SEPARATOR_S
"%s.%d.blist", file
, g_screenname
, gc
->protocol
);
680 if (!stat(path
, &sbuf
)) {
681 debug_printf("%s exists.\n", path
);
684 char path2
[PATHSIZE
];
685 debug_printf("%s does not exist.\n", path
);
686 g_snprintf(path2
, sizeof path2
, "%s" G_DIR_SEPARATOR_S
"%s.blist", file
, g_screenname
);
687 if (!stat(path2
, &sbuf
)) {
688 debug_printf("%s exists, moving to %s\n", path2
, path
);
689 if (rename(path2
, path
))
690 debug_printf("rename didn't work!\n");
696 g_free(g_screenname
);
700 void do_import(struct gaim_connection
*gc
, const char *filename
)
710 g_snprintf(path
, sizeof(path
), "%s", filename
);
712 char *g_screenname
= get_screenname_filename(gc
->username
);
713 char *file
= gaim_user_dir();
715 if (file
!= (char *)NULL
) {
716 sprintf(path
, "%s" G_DIR_SEPARATOR_S
"%s.%d.blist", file
, g_screenname
, gc
->protocol
);
717 g_free(g_screenname
);
719 g_free(g_screenname
);
724 if (stat(path
, &st
)) {
725 debug_printf("Unable to stat %s.\n", path
);
729 if (!(f
= fopen(path
, "r"))) {
730 debug_printf("Unable to open %s.\n", path
);
736 if ((first
[0] == '\n') || (first
[0] == '\r' && first
[1] == '\n'))
739 if (!g_strncasecmp(first
, "Config {", strlen("Config {"))) {
740 /* AIM 4 buddy list */
741 debug_printf("aim 4\n");
743 buf
= translate_blt(f
);
744 } else if (strstr(first
, "group") != NULL
) {
745 /* AIM 3 buddy list */
746 debug_printf("aim 3\n");
748 buf
= translate_lst(f
);
749 } else if (!g_strncasecmp(first
, "[User]", strlen("[User]"))) {
750 /* GnomeICU (hopefully) */
751 debug_printf("gnomeicu\n");
753 buf
= translate_gnomeicu(f
);
754 } else if (first
[0] == 'm') {
755 /* Gaim buddy list - no translation */
756 char buf2
[BUF_LONG
* 2];
757 buf
= g_string_new("");
760 len
= fread(buf2
, 1, BUF_LONG
* 2 - 1, f
);
764 buf
= g_string_append(buf
, buf2
);
765 if (len
!= BUF_LONG
* 2 - 1)
773 buf
= g_string_prepend(buf
, "toc_set_config {");
774 buf
= g_string_append(buf
, "}\n");
775 parse_toc_buddy_list(gc
, buf
->str
);
776 g_string_free(buf
, TRUE
);
780 void do_export(struct gaim_connection
*g
)
789 file
= gaim_user_dir();
794 dir
= fopen(buf
, "r");
796 mkdir(buf
, S_IRUSR
| S_IWUSR
| S_IXUSR
);
800 g_screenname
= get_screenname_filename(g
->username
);
802 sprintf(path
, "%s" G_DIR_SEPARATOR_S
"%s.%d.blist", file
, g_screenname
, g
->protocol
);
803 if ((f
= fopen(path
, "w"))) {
804 debug_printf("writing %s\n", path
);
805 toc_build_config(g
, buf
, 8192 - 1, TRUE
);
806 fprintf(f
, "%s\n", buf
);
808 chmod(path
, S_IRUSR
| S_IWUSR
);
810 debug_printf("unable to write %s\n", path
);
813 g_free(g_screenname
);
816 static gboolean
is_blocked(struct buddy
*b
)
818 struct gaim_connection
*gc
= b
->gc
;
820 if (gc
->permdeny
== PERMIT_ALL
)
823 if (gc
->permdeny
== PERMIT_NONE
) {
824 if (g_strcasecmp(b
->name
, gc
->displayname
))
830 if (gc
->permdeny
== PERMIT_SOME
) {
831 char *x
= g_strdup(normalize(b
->name
));
832 GSList
*s
= gc
->permit
;
834 if (!g_strcasecmp(x
, normalize(s
->data
)))
844 if (gc
->permdeny
== DENY_SOME
) {
845 char *x
= g_strdup(normalize(b
->name
));
846 GSList
*s
= gc
->deny
;
848 if (!g_strcasecmp(x
, normalize(s
->data
)))
861 void signoff_blocked(struct gaim_connection
*gc
)
863 GSList
*g
= gc
->groups
;
865 GSList
*m
= ((struct group
*)g
->data
)->members
;
867 struct buddy
*b
= m
->data
;
869 serv_got_update(gc
, b
->name
, 0, 0, 0, 0, 0, 0);