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
&& i
< sizeof(nm
) - 1)
374 while (*tmp
!= ':' && *tmp
)
382 while (*tmp
&& i
< sizeof(sw
) - 1)
385 if (!find_buddy(gc
, nm
)) {
386 add_buddy(gc
, current
, nm
, sw
);
388 bud
= g_list_append(bud
, c
+ 2);
390 } else if (*c
== 'p') {
391 GSList
*d
= gc
->permit
;
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
));
397 if (!g_strcasecmp(n
, normalize (d
->data
)))
403 gc
->permit
= g_slist_append(gc
->permit
, name
);
407 } else if (*c
== 'd') {
408 GSList
*d
= gc
->deny
;
410 name
= g_malloc(strlen(c
+ 2) + 2);
411 g_snprintf(name
, strlen(c
+ 2) + 1, "%s", c
+ 2);
412 n
= g_strdup(normalize (name
));
414 if (!g_strcasecmp(n
, normalize (d
->data
)))
420 gc
->deny
= g_slist_append(gc
->deny
, name
);
424 } else if (!strncmp("toc", c
, 3)) {
425 sscanf(c
+ strlen(c
) - 1, "%d", &gc
->permdeny
);
426 debug_printf("permdeny: %d\n", gc
->permdeny
);
427 if (gc
->permdeny
== 0)
429 } else if (*c
== 'm') {
430 sscanf(c
+ 2, "%d", &gc
->permdeny
);
431 debug_printf("permdeny: %d\n", gc
->permdeny
);
432 if (gc
->permdeny
== 0)
435 } while ((c
= strtok(NULL
, "\n")));
438 serv_add_buddies(gc
, bud
);
441 serv_set_permit_deny(gc
);
449 void toc_build_config(struct gaim_connection
*gc
, char *s
, int len
, gboolean show
)
451 GSList
*grp
= gc
->groups
;
455 GSList
*plist
= gc
->permit
;
456 GSList
*dlist
= gc
->deny
;
463 pos
+= g_snprintf(&s
[pos
], len
- pos
, "m %d\n", gc
->permdeny
);
464 while (len
> pos
&& grp
) {
465 g
= (struct group
*)grp
->data
;
466 pos
+= g_snprintf(&s
[pos
], len
- pos
, "g %s\n", g
->name
);
468 while (len
> pos
&& mem
) {
469 b
= (struct buddy
*)mem
->data
;
470 pos
+= g_snprintf(&s
[pos
], len
- pos
, "b %s%s%s\n", b
->name
,
471 (show
&& strcmp(b
->name
, b
->show
)) ? ":" : "",
472 (show
&& strcmp(b
->name
, b
->show
)) ? b
->show
: "");
475 grp
= g_slist_next(grp
);
478 while (len
> pos
&& plist
) {
479 pos
+= g_snprintf(&s
[pos
], len
- pos
, "p %s\n", (char *)plist
->data
);
483 while (len
> pos
&& dlist
) {
484 pos
+= g_snprintf(&s
[pos
], len
- pos
, "d %s\n", (char *)dlist
->data
);
489 /* translate an AIM 3 buddylist (*.lst) to a Gaim buddylist */
490 static GString
*translate_lst(FILE *src_fp
)
492 char line
[BUF_LEN
], *line2
;
496 GString
*dest
= g_string_new("m 1\n");
498 while (fgets(line
, BUF_LEN
, src_fp
)) {
499 line2
= g_strchug(line
);
500 if (strstr(line2
, "group") == line2
) {
501 name
= strpbrk(line2
, " \t\n\r\f") + 1;
502 dest
= g_string_append(dest
, "g ");
503 for (i
= 0; i
< strcspn(name
, "\n\r"); i
++)
505 dest
= g_string_append_c(dest
, name
[i
]);
506 dest
= g_string_append_c(dest
, '\n');
508 if (strstr(line2
, "buddy") == line2
) {
509 name
= strpbrk(line2
, " \t\n\r\f") + 1;
510 dest
= g_string_append(dest
, "b ");
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');
522 /* translate an AIM 4 buddylist (*.blt) to Gaim format */
523 static GString
*translate_blt(FILE *src_fp
)
529 GString
*dest
= g_string_new("m 1\n");
531 while (strstr(fgets(line
, BUF_LEN
, src_fp
), "Buddy") == NULL
);
532 while (strstr(fgets(line
, BUF_LEN
, src_fp
), "list") == NULL
);
535 fgets(line
, BUF_LEN
, src_fp
); g_strchomp(line
);
536 if (strchr(line
, '}') != NULL
)
539 if (strchr(line
, '{') != NULL
) {
540 /* Syntax starting with "<group> {" */
542 dest
= g_string_append(dest
, "g ");
543 buddy
= g_strchug(strtok(line
, "{"));
544 for (i
= 0; i
< strlen(buddy
); i
++)
545 if (buddy
[i
] != '\"')
546 dest
= g_string_append_c(dest
, buddy
[i
]);
547 dest
= g_string_append_c(dest
, '\n');
548 while (strchr(fgets(line
, BUF_LEN
, src_fp
), '}') == NULL
) {
549 gboolean pounce
= FALSE
;
552 buddy
= g_strchug(line
);
553 debug_printf("\nbuddy: \"%s\"\n\n", buddy
);
554 dest
= g_string_append(dest
, "b ");
555 if (strchr(buddy
, '{') != NULL
) {
556 /* buddy pounce, etc */
557 char *pos
= strchr(buddy
, '{') - 1;
561 if ((e
= strchr(buddy
, '\"')) != NULL
) {
565 dest
= g_string_append(dest
, buddy
);
566 dest
= g_string_append_c(dest
, '\n');
569 fgets(line
, BUF_LEN
, src_fp
);
570 while (!strchr(line
, '}'));
574 /* Syntax "group buddy buddy ..." */
575 buddy
= g_strchug(strtok(line
, " \n"));
576 dest
= g_string_append(dest
, "g ");
577 if (strchr(buddy
, '\"') != NULL
) {
578 dest
= g_string_append(dest
, &buddy
[1]);
579 dest
= g_string_append_c(dest
, ' ');
580 buddy
= g_strchug(strtok(NULL
, " \n"));
581 while (strchr(buddy
, '\"') == NULL
) {
582 dest
= g_string_append(dest
, buddy
);
583 dest
= g_string_append_c(dest
, ' ');
584 buddy
= g_strchug(strtok(NULL
, " \n"));
586 buddy
[strlen(buddy
) - 1] = '\0';
587 dest
= g_string_append(dest
, buddy
);
589 dest
= g_string_append(dest
, buddy
);
591 dest
= g_string_append_c(dest
, '\n');
592 while ((buddy
= g_strchug(strtok(NULL
, " \n"))) != NULL
) {
593 dest
= g_string_append(dest
, "b ");
594 if (strchr(buddy
, '\"') != NULL
) {
595 dest
= g_string_append(dest
, &buddy
[1]);
596 dest
= g_string_append_c(dest
, ' ');
597 buddy
= g_strchug(strtok(NULL
, " \n"));
598 while (strchr(buddy
, '\"') == NULL
) {
599 dest
= g_string_append(dest
, buddy
);
600 dest
= g_string_append_c(dest
, ' ');
601 buddy
= g_strchug(strtok(NULL
, " \n"));
603 buddy
[strlen(buddy
) - 1] = '\0';
604 dest
= g_string_append(dest
, buddy
);
606 dest
= g_string_append(dest
, buddy
);
608 dest
= g_string_append_c(dest
, '\n');
616 static GString
*translate_gnomeicu(FILE *src_fp
)
619 GString
*dest
= g_string_new("m 1\ng Buddies\n");
621 while (strstr(fgets(line
, BUF_LEN
, src_fp
), "NewContacts") == NULL
);
623 while (fgets(line
, BUF_LEN
, src_fp
)) {
626 if (line
[0] == '\n' || line
[0] == '[')
628 eq
= strchr(line
, '=');
632 eq
= strchr(eq
, ',');
635 dest
= g_string_append(dest
, "b ");
636 dest
= g_string_append(dest
, line
);
637 dest
= g_string_append_c(dest
, '\n');
643 static gchar
*get_screenname_filename(const char *name
)
648 split
= g_strsplit(name
, G_DIR_SEPARATOR_S
, -1);
649 good
= g_strjoinv(NULL
, split
);
657 /* see if a buddy list cache file for this user exists */
659 gboolean
bud_list_cache_exists(struct gaim_connection
*gc
)
661 gboolean ret
= FALSE
;
667 g_screenname
= get_screenname_filename(gc
->username
);
669 file
= gaim_user_dir();
670 if (file
!= (char *)NULL
) {
671 g_snprintf(path
, sizeof path
, "%s/%s.%d.blist", file
, g_screenname
, gc
->protocol
);
672 if (!stat(path
, &sbuf
)) {
673 debug_printf("%s exists.\n", path
);
676 char path2
[PATHSIZE
];
677 debug_printf("%s does not exist.\n", path
);
678 g_snprintf(path2
, sizeof path2
, "%s/%s.blist", file
, g_screenname
);
679 if (!stat(path2
, &sbuf
)) {
680 debug_printf("%s exists, moving to %s\n", path2
, path
);
681 if (rename(path2
, path
))
682 debug_printf("rename didn't work!\n");
689 g_free(g_screenname
);
693 void do_import(struct gaim_connection
*gc
, char *filename
)
703 g_snprintf(path
, sizeof(path
), "%s", filename
);
705 char *g_screenname
= get_screenname_filename(gc
->username
);
706 char *file
= gaim_user_dir();
708 if (file
!= (char *)NULL
) {
709 sprintf(path
, "%s/%s.%d.blist", file
, g_screenname
, gc
->protocol
);
711 g_free(g_screenname
);
713 g_free(g_screenname
);
718 if (stat(path
, &st
)) {
719 debug_printf("Unable to stat %s.\n", path
);
723 if (!(f
= fopen(path
, "r"))) {
724 debug_printf("Unable to open %s.\n", path
);
730 if ((first
[0] == '\n') || (first
[0] == '\r' && first
[1] == '\n'))
733 if (!g_strncasecmp(first
, "Config {", strlen("Config {"))) {
734 /* AIM 4 buddy list */
735 debug_printf("aim 4\n");
737 buf
= translate_blt(f
);
738 } else if (strstr(first
, "group") != NULL
) {
739 /* AIM 3 buddy list */
740 debug_printf("aim 3\n");
742 buf
= translate_lst(f
);
743 } else if (!g_strncasecmp(first
, "[User]", strlen("[User]"))) {
744 /* GnomeICU (hopefully) */
745 debug_printf("gnomeicu\n");
747 buf
= translate_gnomeicu(f
);
748 } else if (first
[0] == 'm') {
749 /* Gaim buddy list - no translation */
750 char buf2
[BUF_LONG
* 2];
751 buf
= g_string_new("");
754 len
= fread(buf2
, 1, BUF_LONG
* 2 - 1, f
);
758 buf
= g_string_append(buf
, buf2
);
759 if (len
!= BUF_LONG
* 2 - 1)
767 buf
= g_string_prepend(buf
, "toc_set_config {");
768 buf
= g_string_append(buf
, "}\n");
769 parse_toc_buddy_list(gc
, buf
->str
);
770 g_string_free(buf
, TRUE
);
774 void do_export(struct gaim_connection
*g
)
783 file
= gaim_user_dir();
788 dir
= fopen(buf
, "r");
790 mkdir(buf
, S_IRUSR
| S_IWUSR
| S_IXUSR
);
794 g_screenname
= get_screenname_filename(g
->username
);
796 sprintf(path
, "%s/%s.%d.blist", file
, g_screenname
, g
->protocol
);
797 if ((f
= fopen(path
, "w"))) {
798 debug_printf("writing %s\n", path
);
799 toc_build_config(g
, buf
, 8192 - 1, TRUE
);
800 fprintf(f
, "%s\n", buf
);
802 chmod(buf
, S_IRUSR
| S_IWUSR
);
804 debug_printf("unable to write %s\n", path
);
807 g_free(g_screenname
);
811 static gboolean
is_blocked(struct buddy
*b
)
813 struct gaim_connection
*gc
= b
->gc
;
815 if (gc
->permdeny
== PERMIT_ALL
)
818 if (gc
->permdeny
== PERMIT_NONE
) {
819 if (g_strcasecmp(b
->name
, gc
->displayname
))
825 if (gc
->permdeny
== PERMIT_SOME
) {
826 char *x
= g_strdup(normalize(b
->name
));
827 GSList
*s
= gc
->permit
;
829 if (!g_strcasecmp(x
, normalize(s
->data
)))
839 if (gc
->permdeny
== DENY_SOME
) {
840 char *x
= g_strdup(normalize(b
->name
));
841 GSList
*s
= gc
->deny
;
843 if (!g_strcasecmp(x
, normalize(s
->data
)))
856 void signoff_blocked(struct gaim_connection
*gc
)
858 GSList
*g
= gc
->groups
;
860 GSList
*m
= ((struct group
*)g
->data
)->members
;
862 struct buddy
*b
= m
->data
;
864 serv_got_update(gc
, b
->name
, 0, 0, 0, 0, 0, 0);