comparison src/list.c @ 4349:0c68d402f59f

[gaim-migrate @ 4614] XML Blist Gaim stores all the buddy lists in one big happy file now. You can order the buddies however you want, and they'll stay ordered that way. We can also store some per-buddy information now, which will be cool. committer: Tailor Script <tailor@pidgin.im>
author Nathan Walp <nwalp@pidgin.im>
date Sun, 19 Jan 2003 22:16:52 +0000
parents a614423c648f
children bd1db4c2e00b
comparison
equal deleted inserted replaced
4348:922b66840a51 4349:0c68d402f59f
21 21
22 #ifdef HAVE_CONFIG_H 22 #ifdef HAVE_CONFIG_H
23 #include <config.h> 23 #include <config.h>
24 #endif 24 #endif
25 #include <string.h> 25 #include <string.h>
26 #include <stdlib.h>
26 #include <sys/types.h> 27 #include <sys/types.h>
27 #include <sys/stat.h> 28 #include <sys/stat.h>
28 #ifndef _WIN32 29 #ifndef _WIN32
29 #include <unistd.h> 30 #include <unistd.h>
30 #else 31 #else
31 #include <direct.h> 32 #include <direct.h>
32 #endif 33 #endif
34 #include <ctype.h>
33 #include "gaim.h" 35 #include "gaim.h"
34 #include "prpl.h" 36 #include "prpl.h"
35 37
36 #ifdef _WIN32 38 #ifdef _WIN32
37 #include "win32dep.h" 39 #include "win32dep.h"
38 #endif 40 #endif
39 41
40 #define PATHSIZE 1024 42 #define PATHSIZE 1024
41 43
42 void remove_buddy(struct gaim_connection *gc, struct group *rem_g, struct buddy *rem_b) 44 void remove_buddy(struct buddy *rem_b)
43 { 45 {
44 GSList *grp; 46 if(rem_b->user->gc) {
45 GSList *mem; 47 struct group *rem_g = find_group_by_buddy(rem_b);
46 48
47 struct group *delg; 49 ui_remove_buddy(rem_b);
48 struct buddy *delb; 50
49 51 rem_g->members = g_slist_remove(rem_g->members, rem_b);
50 /* we assume that gc is not NULL and that the buddy exists somewhere within the 52
51 * gc's buddy list, therefore we can safely remove it. we need to ensure this 53 g_hash_table_destroy(rem_b->settings);
52 * via the UI 54
53 */ 55 g_free(rem_b);
54 56 } else {
55 grp = g_slist_find(gc->groups, rem_g); 57 char *buf = g_strdup_printf(_("%s was not removed from your buddy "
56 delg = (struct group *)grp->data; 58 "list, because your account (%s) is not logged in."),
57 mem = delg->members; 59 rem_b->name, rem_b->user->username);
58 60 do_error_dialog(_("Buddy Not Removed"), buf, GAIM_ERROR);
59 mem = g_slist_find(mem, rem_b); 61 g_free(buf);
60 delb = (struct buddy *)mem->data; 62 }
61 63 }
62 delg->members = g_slist_remove(delg->members, delb); 64
63 65 void remove_group(struct group *rem_g)
64 ui_remove_buddy(gc, rem_g, rem_b); 66 {
65 67 GSList *users;
66 g_free(rem_b); 68
67 69 for(users = aim_users; users; users = users->next) {
68 /* we don't flush buddy list to cache because in the case of remove_group that would 70 struct aim_user *user = users->data;
69 * mean writing to the buddy list file once for each buddy, plus one more time */ 71 if(user->gc) {
70 } 72 GList *tmp = NULL;
71 73 GSList *buds = rem_g->members;
72 void remove_group(struct gaim_connection *gc, struct group *rem_g) 74
73 { 75 while (buds) {
74 GSList *grp; 76 struct buddy *delb = (struct buddy *)buds->data;
75 GSList *mem; 77 buds = buds->next;
76 GList *tmp = NULL; 78
77 79 if(delb->user == user) {
78 struct group *delg; 80 tmp = g_list_append(tmp, g_strdup(delb->name));
79 struct buddy *delb; 81 remove_buddy(delb); /* this should take care of removing
80 82 the group_show if necessary */
81 /* we assume that the group actually does exist within the gc, and that the gc is not NULL. 83 }
82 * the UI is responsible for this */ 84 }
83 85
84 grp = g_slist_find(gc->groups, rem_g); 86 if(tmp)
85 delg = (struct group *)grp->data; 87 serv_remove_buddies(user->gc, tmp, rem_g->name);
86 mem = delg->members; 88
87 89 while (tmp) {
88 while (delg->members) { 90 g_free(tmp->data);
89 delb = (struct buddy *)delg->members->data; 91 tmp = g_list_remove(tmp, tmp->data);
90 tmp = g_list_append(tmp, g_strdup(delb->name)); 92 }
91 remove_buddy(gc, delg, delb); /* this should take care of removing 93 }
92 the group_show if necessary */ 94 }
93 } 95
94 96 if(rem_g->members) {
95 gc->groups = g_slist_remove(gc->groups, delg); 97 char *buf = g_strdup_printf(_("%d buddies from group %s were not "
96 98 "removed because their accounts were not logged in. These "
97 serv_remove_buddies(gc, tmp, rem_g->name); 99 "buddies, and the group were not removed.\n"),
98 while (tmp) { 100 g_slist_length(rem_g->members), rem_g->name);
99 g_free(tmp->data); 101 do_error_dialog(_("Group Not Removed"), buf, GAIM_ERROR);
100 tmp = g_list_remove(tmp, tmp->data); 102 g_free(buf);
101 } 103
102 104 return;
103 ui_remove_group(gc, rem_g); 105 }
106
107 ui_remove_group(rem_g);
108
109 groups = g_slist_remove(groups, rem_g);
104 110
105 g_free(rem_g); 111 g_free(rem_g);
106 112
107 /* don't flush buddy list to cache in order to be consistent with remove_buddy, 113 /* 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. */ 114 * mostly. remove_group is only called from one place, so we'll let it handle it. */
109 } 115 }
110 116
111 struct buddy *add_buddy(struct gaim_connection *gc, const char *group, const char *buddy, const char *show) 117 struct buddy *add_buddy(struct aim_user *user, const char *group, const char *buddy, const char *show)
112 { 118 {
113 struct buddy *b; 119 struct buddy *b;
114 struct group *g; 120 struct group *g;
115 const char *good; 121 const char *good;
116 122
117 if (!g_slist_find(connections, gc)) 123 if ((b = find_buddy(user, buddy)) != NULL)
118 return NULL;
119
120 if ((b = find_buddy(gc, buddy)) != NULL)
121 return b; 124 return b;
122 125
123 g = find_group(gc, group); 126 g = find_group(group);
124 127
125 if (g == NULL) 128 if (g == NULL)
126 g = add_group(gc, group); 129 g = add_group(group);
127 130
128 b = (struct buddy *)g_new0(struct buddy, 1); 131 b = (struct buddy *)g_new0(struct buddy, 1);
129 132
130 if (!b) 133 if (!b)
131 return NULL; 134 return NULL;
132 135
133 b->gc = gc; 136 b->user = user;
134 b->present = 0; 137 b->present = 0;
135 138
136 if (gc->prpl->normalize) 139 b->settings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
137 good = gc->prpl->normalize(buddy); 140
138 else 141 good = buddy;
139 good = buddy;
140 142
141 g_snprintf(b->name, sizeof(b->name), "%s", good); 143 g_snprintf(b->name, sizeof(b->name), "%s", good);
142 if(show && show[0]) 144 if(show && show[0])
143 g_snprintf(b->alias, sizeof(b->alias), "%s", show); 145 g_snprintf(b->alias, sizeof(b->alias), "%s", show);
144 else 146 else
147 g->members = g_slist_append(g->members, b); 149 g->members = g_slist_append(g->members, b);
148 150
149 b->idle = 0; 151 b->idle = 0;
150 b->caps = 0; 152 b->caps = 0;
151 153
152 ui_add_buddy(gc, g, b); 154 ui_add_buddy(user->gc, g, b);
153 155
154 return b; 156 return b;
155 } 157 }
156 158
157 struct group *add_group(struct gaim_connection *gc, const char *group) 159 struct group *add_group(const char *group)
158 { 160 {
159 struct group *g = find_group(gc, group); 161 struct group *g = find_group(group);
160 if (g) 162 if (g)
161 return g; 163 return g;
162 if (!g_slist_find(connections, gc))
163 return NULL;
164 g = (struct group *)g_new0(struct group, 1); 164 g = (struct group *)g_new0(struct group, 1);
165 if (!g) 165 if (!g)
166 return NULL; 166 return NULL;
167 167
168 g->gc = gc;
169 strncpy(g->name, group, sizeof(g->name)); 168 strncpy(g->name, group, sizeof(g->name));
170 gc->groups = g_slist_append(gc->groups, g); 169 groups = g_slist_append(groups, g);
171 170
172 g->members = NULL; 171 g->members = NULL;
173 172
174 ui_add_group(gc, g); 173 ui_add_group(g);
175 174
176 return g; 175 return g;
177 } 176 }
178 177
179 struct group *find_group(struct gaim_connection *gc, const char *group) 178 struct group *find_group(const char *group)
180 { 179 {
181 struct group *g; 180 struct group *g;
182 GSList *grp; 181 GSList *grp;
183 GSList *c = connections; 182 char *grpname = g_strdup(normalize(group));
184 struct gaim_connection *z; 183
185 char *grpname = g_malloc(strlen(group) + 1); 184 grp = groups;
186 185 while (grp) {
187 strcpy(grpname, normalize (group)); 186 g = (struct group *)grp->data;
188 if (gc) { 187 if (!g_strcasecmp(normalize (g->name), grpname)) {
189 if (!g_slist_find(connections, gc)) 188 g_free(grpname);
190 return NULL; 189 return g;
191 grp = gc->groups; 190 }
192 while (grp) { 191 grp = g_slist_next(grp);
193 g = (struct group *)grp->data; 192 }
194 if (!g_strcasecmp(normalize (g->name), grpname)) { 193 g_free(grpname);
195 g_free(grpname); 194 return NULL;
196 return g; 195 }
197 } 196
198 grp = g_slist_next(grp); 197 struct group *find_group_by_buddy(struct buddy *b)
199 } 198 {
200 199 GSList *grp = groups;
201 g_free(grpname); 200
202 return NULL; 201 while(grp) {
203 } else { 202 struct group *g = grp->data;
204 while (c) { 203 if(g_slist_find(g->members, b))
205 z = (struct gaim_connection *)c->data; 204 return g;
206 grp = z->groups; 205 grp = grp->next;
207 while (grp) { 206 }
208 g = (struct group *)grp->data; 207 return NULL;
209 if (!g_strcasecmp(normalize (g->name), grpname)) { 208 }
210 g_free(grpname); 209
211 return g; 210 struct buddy *find_buddy(struct aim_user *user, const char *who)
212 }
213 grp = g_slist_next(grp);
214 }
215
216 c = c->next;
217 }
218 g_free(grpname);
219 return NULL;
220 }
221 }
222
223 struct group *find_group_by_buddy(struct gaim_connection *gc, const char *who)
224 { 211 {
225 struct group *g; 212 struct group *g;
226 struct buddy *b; 213 struct buddy *b;
227 GSList *grp; 214 GSList *grp;
228 GSList *mem; 215 GSList *mem;
229 char *whoname; 216 char *whoname = NULL;
230 char *(*norm)(const char *); 217 char *(*norm)(const char *);
231 218
232 if (gc) { 219 grp = groups;
233 if (gc->prpl->normalize) 220 while (grp) {
234 norm = gc->prpl->normalize; 221 g = (struct group *)grp->data;
235 else 222
223 mem = g->members;
224 while (mem) {
225 b = (struct buddy *)mem->data;
226 /*
227 norm = (b->user->gc && b->user->gc->prpl->normalize) ? b->user->gc->prpl->normalize : normalize;
228 */
236 norm = normalize; 229 norm = normalize;
237 whoname = g_strdup(norm(who)); 230 whoname = g_strdup(norm(who));
238 grp = gc->groups; 231 if ((b->user == user || !user) && !strcmp(norm(b->name), whoname)) {
239 while (grp) { 232 g_free(whoname);
240 g = (struct group *)grp->data; 233 return b;
241
242 mem = g->members;
243 while (mem) {
244 b = (struct buddy *)mem->data;
245 if (!strcmp(norm(b->name), whoname)) {
246 g_free(whoname);
247 return g;
248 }
249 mem = mem->next;
250 } 234 }
251 grp = g_slist_next(grp);
252 }
253 g_free(whoname);
254 return NULL;
255 } else {
256 GSList *c = connections;
257 struct gaim_connection *z;
258 while (c) {
259 z = (struct gaim_connection *)c->data;
260 if (z->prpl->normalize)
261 norm = z->prpl->normalize;
262 else
263 norm = normalize;
264 whoname = g_strdup(norm(who));
265 grp = z->groups;
266 while (grp) {
267 g = (struct group *)grp->data;
268
269 mem = g->members;
270 while (mem) {
271 b = (struct buddy *)mem->data;
272 if (!strcmp(norm(b->name), whoname)) {
273 g_free(whoname);
274 return g;
275 }
276 mem = mem->next;
277 }
278 grp = g_slist_next(grp);
279 }
280 c = c->next;
281 g_free(whoname); 235 g_free(whoname);
282 } 236 mem = mem->next;
283 return NULL; 237 }
284 } 238 grp = g_slist_next(grp);
285 } 239 }
286 240 return NULL;
287 struct buddy *find_buddy(struct gaim_connection *gc, const char *who) 241 }
288 { 242
289 struct group *g; 243 void parse_toc_buddy_list(struct aim_user *user, char *config)
290 struct buddy *b;
291 GSList *grp;
292 GSList *c;
293 struct gaim_connection *z;
294 GSList *mem;
295 char *whoname;
296 char *(*norm)(const char *);
297
298 if (gc) {
299 if (!g_slist_find(connections, gc))
300 return NULL;
301 if (gc->prpl->normalize)
302 norm = gc->prpl->normalize;
303 else
304 norm = normalize;
305 whoname = g_strdup(norm(who));
306 grp = gc->groups;
307 while (grp) {
308 g = (struct group *)grp->data;
309
310 mem = g->members;
311 while (mem) {
312 b = (struct buddy *)mem->data;
313 if (!strcmp(norm(b->name), whoname)) {
314 g_free(whoname);
315 return b;
316 }
317 mem = mem->next;
318 }
319 grp = g_slist_next(grp);
320 }
321 g_free(whoname);
322 return NULL;
323 } else {
324 c = connections;
325 while (c) {
326 z = (struct gaim_connection *)c->data;
327 if (z->prpl->normalize)
328 norm = z->prpl->normalize;
329 else
330 norm = normalize;
331 whoname = g_strdup(norm(who));
332 grp = z->groups;
333 while (grp) {
334 g = (struct group *)grp->data;
335
336 mem = g->members;
337 while (mem) {
338 b = (struct buddy *)mem->data;
339 if (!strcmp(norm(b->name), whoname)) {
340 g_free(whoname);
341 return b;
342 }
343 mem = mem->next;
344 }
345 grp = g_slist_next(grp);
346 }
347 c = c->next;
348 g_free(whoname);
349 }
350 return NULL;
351 }
352 }
353
354 void parse_toc_buddy_list(struct gaim_connection *gc, char *config)
355 { 244 {
356 char *c; 245 char *c;
357 char current[256]; 246 char current[256];
358 char *name; 247
359 GList *bud; 248
360 int how_many = 0;
361
362 bud = NULL;
363
364 if (config != NULL) { 249 if (config != NULL) {
365 250
366 /* skip "CONFIG:" (if it exists) */ 251 /* skip "CONFIG:" (if it exists) */
367 c = strncmp(config + 6 /* sizeof(struct sflap_hdr) */ , "CONFIG:", strlen("CONFIG:")) ? 252 c = strncmp(config + 6 /* sizeof(struct sflap_hdr) */ , "CONFIG:", strlen("CONFIG:")) ?
368 strtok(config, "\n") : 253 strtok(config, "\n") :
369 strtok(config + 6 /* sizeof(struct sflap_hdr) */ + strlen("CONFIG:"), "\n"); 254 strtok(config + 6 /* sizeof(struct sflap_hdr) */ + strlen("CONFIG:"), "\n");
370 do { 255 do {
371 if (c == NULL) 256 if (c == NULL)
372 break; 257 break;
373 if (*c == 'g') { 258 if (*c == 'g') {
374 strncpy(current, c + 2, sizeof(current)); 259 strncpy(current, c + 2, sizeof(current));
375 if (!find_group(gc, current)) { 260 if (!find_group(current)) {
376 add_group(gc, current); 261 add_group(current);
377 how_many++;
378 } 262 }
379 } else if (*c == 'b' && !find_buddy(gc, c + 2)) { 263 } else if (*c == 'b' && !find_buddy(user, c + 2)) {
380 char nm[80], sw[BUDDY_ALIAS_MAXLEN], *tmp = c + 2; 264 char nm[80], sw[BUDDY_ALIAS_MAXLEN], *tmp = c + 2;
381 int i = 0; 265 int i = 0;
382 while (*tmp != ':' && *tmp && i < sizeof(nm) - 1) 266 while (*tmp != ':' && *tmp && i < sizeof(nm) - 1)
383 nm[i++] = *tmp++; 267 nm[i++] = *tmp++;
384 268
385 while (*tmp != ':' && *tmp) 269 while (*tmp != ':' && *tmp)
386 tmp++; 270 tmp++;
387 271
388 if (*tmp == ':') 272 if (*tmp == ':')
389 *tmp++ = '\0'; 273 *tmp++ = '\0';
390 274
391 nm[i] = '\0'; 275 nm[i] = '\0';
392 i = 0; 276 i = 0;
393 while (*tmp && i < sizeof(sw) - 1) 277 while (*tmp && i < sizeof(sw) - 1)
394 sw[i++] = *tmp++; 278 sw[i++] = *tmp++;
395 sw[i] = '\0'; 279 sw[i] = '\0';
396 if (!find_buddy(gc, nm)) { 280 if (!find_buddy(user, nm)) {
397 add_buddy(gc, current, nm, sw); 281 add_buddy(user, current, nm, sw);
398 how_many++;
399 bud = g_list_append(bud, c + 2);
400 } 282 }
401 } else if (*c == 'p') { 283 } else if (*c == 'p') {
402 GSList *d = gc->permit; 284 gaim_privacy_permit_add(user, c + 2);
403 char *n;
404 name = g_malloc(strlen(c + 2) + 2);
405 g_snprintf(name, strlen(c + 2) + 1, "%s", c + 2);
406 n = g_strdup(normalize (name));
407 while (d) {
408 if (!g_strcasecmp(n, normalize (d->data)))
409 break;
410 d = d->next;
411 }
412 g_free(n);
413 if (!d) {
414 gc->permit = g_slist_append(gc->permit, name);
415 how_many++;
416 } else
417 g_free(name);
418 } else if (*c == 'd') { 285 } else if (*c == 'd') {
419 GSList *d = gc->deny; 286 gaim_privacy_deny_add(user, c + 2);
420 char *n;
421 name = g_malloc(strlen(c + 2) + 2);
422 g_snprintf(name, strlen(c + 2) + 1, "%s", c + 2);
423 n = g_strdup(normalize (name));
424 while (d) {
425 if (!g_strcasecmp(n, normalize (d->data)))
426 break;
427 d = d->next;
428 }
429 g_free(n);
430 if (!d) {
431 gc->deny = g_slist_append(gc->deny, name);
432 how_many++;
433 } else
434 g_free(name);
435 } else if (!strncmp("toc", c, 3)) { 287 } else if (!strncmp("toc", c, 3)) {
436 sscanf(c + strlen(c) - 1, "%d", &gc->permdeny); 288 sscanf(c + strlen(c) - 1, "%d", &user->permdeny);
437 debug_printf("permdeny: %d\n", gc->permdeny); 289 debug_printf("permdeny: %d\n", user->permdeny);
438 if (gc->permdeny == 0) 290 if (user->permdeny == 0)
439 gc->permdeny = 1; 291 user->permdeny = 1;
440 } else if (*c == 'm') { 292 } else if (*c == 'm') {
441 sscanf(c + 2, "%d", &gc->permdeny); 293 sscanf(c + 2, "%d", &user->permdeny);
442 debug_printf("permdeny: %d\n", gc->permdeny); 294 debug_printf("permdeny: %d\n", user->permdeny);
443 if (gc->permdeny == 0) 295 if (user->permdeny == 0)
444 gc->permdeny = 1; 296 user->permdeny = 1;
445 } 297 }
446 } while ((c = strtok(NULL, "\n"))); 298 } while ((c = strtok(NULL, "\n")));
447 299 }
448 if (bud != NULL) { 300 }
449 serv_add_buddies(gc, bud); 301
450 g_list_free(bud); 302 void toc_build_config(struct aim_user *user, char *s, int len, gboolean show)
451 } 303 {
452 serv_set_permit_deny(gc); 304 GSList *grp = groups;
453 }
454
455 if (how_many != 0)
456 do_export(gc);
457
458 }
459
460 void toc_build_config(struct gaim_connection *gc, char *s, int len, gboolean show)
461 {
462 GSList *grp = gc->groups;
463 GSList *mem; 305 GSList *mem;
464 struct group *g; 306 struct group *g;
465 struct buddy *b; 307 struct buddy *b;
466 GSList *plist = gc->permit; 308 GSList *plist = user->permit;
467 GSList *dlist = gc->deny; 309 GSList *dlist = user->deny;
468 310
469 int pos = 0; 311 int pos = 0;
470 312
471 if (!gc->permdeny) 313 if (!user->permdeny)
472 gc->permdeny = 1; 314 user->permdeny = 1;
473 315
474 pos += g_snprintf(&s[pos], len - pos, "m %d\n", gc->permdeny); 316 pos += g_snprintf(&s[pos], len - pos, "m %d\n", user->permdeny);
475 while (len > pos && grp) { 317 while (len > pos && grp) {
476 g = (struct group *)grp->data; 318 g = (struct group *)grp->data;
477 pos += g_snprintf(&s[pos], len - pos, "g %s\n", g->name); 319 if(gaim_group_on_account(g, user)) {
478 mem = g->members; 320 pos += g_snprintf(&s[pos], len - pos, "g %s\n", g->name);
479 while (len > pos && mem) { 321 mem = g->members;
480 b = (struct buddy *)mem->data; 322 while (len > pos && mem) {
481 pos += g_snprintf(&s[pos], len - pos, "b %s%s%s\n", b->name, 323 b = (struct buddy *)mem->data;
482 (show && b->alias[0]) ? ":" : "", 324 if(b->user == user) {
483 (show && b->alias[0]) ? b->alias : ""); 325 pos += g_snprintf(&s[pos], len - pos, "b %s%s%s\n", b->name,
484 mem = mem->next; 326 (show && b->alias[0]) ? ":" : "",
327 (show && b->alias[0]) ? b->alias : "");
328 }
329 mem = mem->next;
330 }
485 } 331 }
486 grp = g_slist_next(grp); 332 grp = g_slist_next(grp);
487 } 333 }
488 334
489 while (len > pos && plist) { 335 while (len > pos && plist) {
663 g_strup(good); 509 g_strup(good);
664 510
665 return good; 511 return good;
666 } 512 }
667 513
668 /* see if a buddy list cache file for this user exists */ 514 static gboolean gaim_blist_read(const char *filename);
669 515
670 gboolean bud_list_cache_exists(struct gaim_connection *gc) 516 void do_import(struct aim_user *user, const char *filename)
671 {
672 gboolean ret = FALSE;
673 char path[PATHSIZE];
674 char *file;
675 struct stat sbuf;
676 char *g_screenname;
677
678 g_screenname = get_screenname_filename(gc->username);
679
680 file = gaim_user_dir();
681 if (file != (char *)NULL) {
682 g_snprintf(path, sizeof path, "%s" G_DIR_SEPARATOR_S "%s.%d.blist", file, g_screenname, gc->protocol);
683 if (!stat(path, &sbuf)) {
684 debug_printf("%s exists.\n", path);
685 ret = TRUE;
686 } else {
687 char path2[PATHSIZE];
688 debug_printf("%s does not exist.\n", path);
689 g_snprintf(path2, sizeof path2, "%s" G_DIR_SEPARATOR_S "%s.blist", file, g_screenname);
690 if (!stat(path2, &sbuf)) {
691 debug_printf("%s exists, moving to %s\n", path2, path);
692 if (rename(path2, path))
693 debug_printf("rename didn't work!\n");
694 else
695 ret = TRUE;
696 }
697 }
698 }
699 g_free(g_screenname);
700 return ret;
701 }
702
703 void do_import(struct gaim_connection *gc, const char *filename)
704 { 517 {
705 GString *buf = NULL; 518 GString *buf = NULL;
706 char first[64]; 519 char first[64];
707 char path[PATHSIZE]; 520 char path[PATHSIZE];
708 int len; 521 int len;
710 struct stat st; 523 struct stat st;
711 524
712 if (filename) { 525 if (filename) {
713 g_snprintf(path, sizeof(path), "%s", filename); 526 g_snprintf(path, sizeof(path), "%s", filename);
714 } else { 527 } else {
715 char *g_screenname = get_screenname_filename(gc->username); 528 char *g_screenname = get_screenname_filename(user->username);
716 char *file = gaim_user_dir(); 529 char *file = gaim_user_dir();
530 int protocol = (user->protocol == PROTO_OSCAR) ? (isalpha(user->username[0]) ? PROTO_TOC : PROTO_ICQ): user->protocol;
717 531
718 if (file != (char *)NULL) { 532 if (file != (char *)NULL) {
719 sprintf(path, "%s" G_DIR_SEPARATOR_S "%s.%d.blist", file, g_screenname, gc->protocol); 533 sprintf(path, "%s" G_DIR_SEPARATOR_S "%s.%d.blist", file, g_screenname, protocol);
720 g_free(g_screenname); 534 g_free(g_screenname);
721 } else { 535 } else {
722 g_free(g_screenname); 536 g_free(g_screenname);
723 return; 537 return;
724 } 538 }
737 fgets(first, 64, f); 551 fgets(first, 64, f);
738 552
739 if ((first[0] == '\n') || (first[0] == '\r' && first[1] == '\n')) 553 if ((first[0] == '\n') || (first[0] == '\r' && first[1] == '\n'))
740 fgets(first, 64, f); 554 fgets(first, 64, f);
741 555
742 if (!g_strncasecmp(first, "Config {", strlen("Config {"))) { 556 if (!g_strncasecmp(first, "<xml", strlen("<xml"))) {
557 /* new gaim XML buddy list */
558 gaim_blist_read(path);
559 } else if (!g_strncasecmp(first, "Config {", strlen("Config {"))) {
743 /* AIM 4 buddy list */ 560 /* AIM 4 buddy list */
744 debug_printf("aim 4\n"); 561 debug_printf("aim 4\n");
745 rewind(f); 562 rewind(f);
746 buf = translate_blt(f); 563 buf = translate_blt(f);
747 } else if (strstr(first, "group") != NULL) { 564 } else if (strstr(first, "group") != NULL) {
773 fclose(f); 590 fclose(f);
774 591
775 if (buf) { 592 if (buf) {
776 buf = g_string_prepend(buf, "toc_set_config {"); 593 buf = g_string_prepend(buf, "toc_set_config {");
777 buf = g_string_append(buf, "}\n"); 594 buf = g_string_append(buf, "}\n");
778 parse_toc_buddy_list(gc, buf->str); 595 parse_toc_buddy_list(user, buf->str);
779 g_string_free(buf, TRUE); 596 g_string_free(buf, TRUE);
780 } 597 }
781 } 598 }
782 599
783 void do_export(struct gaim_connection *g)
784 {
785 FILE *dir;
786 FILE *f;
787 char buf[32 * 1024];
788 char *file;
789 char path[PATHSIZE];
790 char *g_screenname;
791
792 file = gaim_user_dir();
793 if (!file)
794 return;
795
796 strcpy(buf, file);
797 dir = fopen(buf, "r");
798 if (!dir)
799 mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR);
800 else
801 fclose(dir);
802
803 g_screenname = get_screenname_filename(g->username);
804
805 sprintf(path, "%s" G_DIR_SEPARATOR_S "%s.%d.blist", file, g_screenname, g->protocol);
806 if ((f = fopen(path, "w"))) {
807 debug_printf("writing %s\n", path);
808 toc_build_config(g, buf, 8192 - 1, TRUE);
809 fprintf(f, "%s\n", buf);
810 fclose(f);
811 chmod(path, S_IRUSR | S_IWUSR);
812 } else {
813 debug_printf("unable to write %s\n", path);
814 }
815
816 g_free(g_screenname);
817 }
818
819 static gboolean is_blocked(struct buddy *b) 600 static gboolean is_blocked(struct buddy *b)
820 { 601 {
821 struct gaim_connection *gc = b->gc; 602 struct aim_user *user = b->user;
822 603
823 if (gc->permdeny == PERMIT_ALL) 604 if (user->permdeny == PERMIT_ALL)
824 return FALSE; 605 return FALSE;
825 606
826 if (gc->permdeny == PERMIT_NONE) { 607 if (user->permdeny == PERMIT_NONE) {
827 if (g_strcasecmp(b->name, gc->displayname)) 608 if (user->gc && g_strcasecmp(b->name, user->gc->username))
828 return TRUE; 609 return TRUE;
829 else 610 else
830 return FALSE; 611 return FALSE;
831 } 612 }
832 613
833 if (gc->permdeny == PERMIT_SOME) { 614 if (user->permdeny == PERMIT_SOME) {
834 char *x = g_strdup(normalize(b->name)); 615 char *x = g_strdup(normalize(b->name));
835 GSList *s = gc->permit; 616 GSList *s = user->permit;
836 while (s) { 617 while (s) {
837 if (!g_strcasecmp(x, normalize(s->data))) 618 if (!g_strcasecmp(x, normalize(s->data)))
838 break; 619 break;
839 s = s->next; 620 s = s->next;
840 } 621 }
842 if (s) 623 if (s)
843 return FALSE; 624 return FALSE;
844 return TRUE; 625 return TRUE;
845 } 626 }
846 627
847 if (gc->permdeny == DENY_SOME) { 628 if (user->permdeny == DENY_SOME) {
848 char *x = g_strdup(normalize(b->name)); 629 char *x = g_strdup(normalize(b->name));
849 GSList *s = gc->deny; 630 GSList *s = user->deny;
850 while (s) { 631 while (s) {
851 if (!g_strcasecmp(x, normalize(s->data))) 632 if (!g_strcasecmp(x, normalize(s->data)))
852 break; 633 break;
853 s = s->next; 634 s = s->next;
854 } 635 }
861 return FALSE; 642 return FALSE;
862 } 643 }
863 644
864 void signoff_blocked(struct gaim_connection *gc) 645 void signoff_blocked(struct gaim_connection *gc)
865 { 646 {
866 GSList *g = gc->groups; 647 GSList *g = groups;
867 while (g) { 648 while (g) {
868 GSList *m = ((struct group *)g->data)->members; 649 GSList *m = ((struct group *)g->data)->members;
869 while (m) { 650 while (m) {
870 struct buddy *b = m->data; 651 struct buddy *b = m->data;
871 if (is_blocked(b)) 652 if (is_blocked(b))
892 if(!ret) 673 if(!ret)
893 return b ? b->name : _("Unknown"); 674 return b ? b->name : _("Unknown");
894 return ret; 675 return ret;
895 } 676 }
896 677
678 GSList *gaim_group_get_accounts(struct group *g) {
679 GSList *buds = g->members;
680 GSList *ret = NULL;
681 while(buds) {
682 struct buddy *b = buds->data;
683 if(!g_slist_find(ret, b->user))
684 ret = g_slist_append(ret, b->user);
685 buds = buds->next;
686 }
687 return ret;
688 }
689
690 gboolean gaim_group_on_account(struct group *g, struct aim_user *user) {
691 GSList *buds = g->members;
692 while(buds) {
693 struct buddy *b = buds->data;
694 if((!user && b->user->gc) || b->user == user)
695 return TRUE;
696 buds = buds->next;
697 }
698 return FALSE;
699 }
700
701
702 static char *blist_parser_group_name = NULL;
703 static char *blist_parser_person_name = NULL;
704 static char *blist_parser_account_name = NULL;
705 static int blist_parser_account_protocol = 0;
706 static char *blist_parser_buddy_name = NULL;
707 static char *blist_parser_buddy_alias = NULL;
708 static char *blist_parser_setting_name = NULL;
709 static char *blist_parser_setting_value = NULL;
710 static GHashTable *blist_parser_buddy_settings = NULL;
711 static int blist_parser_privacy_mode = 0;
712 static enum {
713 BLIST_TAG_GAIM,
714 BLIST_TAG_BLIST,
715 BLIST_TAG_GROUP,
716 BLIST_TAG_PERSON,
717 BLIST_TAG_BUDDY,
718 BLIST_TAG_NAME,
719 BLIST_TAG_ALIAS,
720 BLIST_TAG_SETTING,
721 BLIST_TAG_PRIVACY,
722 BLIST_TAG_ACCOUNT,
723 BLIST_TAG_PERMIT,
724 BLIST_TAG_BLOCK,
725 BLIST_TAG_IGNORE
726 } blist_parser_current_tag;
727
728 static void blist_start_element_handler (GMarkupParseContext *context,
729 const gchar *element_name,
730 const gchar **attribute_names,
731 const gchar **attribute_values,
732 gpointer user_data,
733 GError **error) {
734 int i;
735
736 if(!strcmp(element_name, "gaim")) {
737 blist_parser_current_tag = BLIST_TAG_GAIM;
738 } else if(!strcmp(element_name, "blist")) {
739 blist_parser_current_tag = BLIST_TAG_BLIST;
740 } else if(!strcmp(element_name, "group")) {
741 blist_parser_current_tag = BLIST_TAG_GROUP;
742 for(i=0; attribute_names[i]; i++) {
743 if(!strcmp(attribute_names[i], "name"))
744 blist_parser_group_name = g_strdup(attribute_values[i]);
745 }
746 if(blist_parser_group_name) {
747 add_group(blist_parser_group_name);
748 }
749 } else if(!strcmp(element_name, "person")) {
750 blist_parser_current_tag = BLIST_TAG_PERSON;
751 for(i=0; attribute_names[i]; i++) {
752 if(!strcmp(attribute_names[i], "name"))
753 blist_parser_person_name = g_strdup(attribute_values[i]);
754 }
755 } else if(!strcmp(element_name, "buddy")) {
756 blist_parser_current_tag = BLIST_TAG_BUDDY;
757 for(i=0; attribute_names[i]; i++) {
758 if(!strcmp(attribute_names[i], "account"))
759 blist_parser_account_name = g_strdup(attribute_values[i]);
760 else if(!strcmp(attribute_names[i], "protocol"))
761 blist_parser_account_protocol = atoi(attribute_values[i]);
762 }
763 } else if(!strcmp(element_name, "name")) {
764 blist_parser_current_tag = BLIST_TAG_NAME;
765 } else if(!strcmp(element_name, "alias")) {
766 blist_parser_current_tag = BLIST_TAG_ALIAS;
767 } else if(!strcmp(element_name, "setting")) {
768 blist_parser_current_tag = BLIST_TAG_SETTING;
769 for(i=0; attribute_names[i]; i++) {
770 if(!strcmp(attribute_names[i], "name"))
771 blist_parser_setting_name = g_strdup(attribute_values[i]);
772 }
773 } else if(!strcmp(element_name, "privacy")) {
774 blist_parser_current_tag = BLIST_TAG_PRIVACY;
775 } else if(!strcmp(element_name, "account")) {
776 blist_parser_current_tag = BLIST_TAG_ACCOUNT;
777 for(i=0; attribute_names[i]; i++) {
778 if(!strcmp(attribute_names[i], "protocol"))
779 blist_parser_account_protocol = atoi(attribute_values[i]);
780 else if(!strcmp(attribute_names[i], "mode"))
781 blist_parser_privacy_mode = atoi(attribute_values[i]);
782 else if(!strcmp(attribute_names[i], "name"))
783 blist_parser_account_name = g_strdup(attribute_values[i]);
784 }
785 } else if(!strcmp(element_name, "permit")) {
786 blist_parser_current_tag = BLIST_TAG_PERMIT;
787 } else if(!strcmp(element_name, "block")) {
788 blist_parser_current_tag = BLIST_TAG_BLOCK;
789 } else if(!strcmp(element_name, "ignore")) {
790 blist_parser_current_tag = BLIST_TAG_IGNORE;
791 }
792 }
793
794 static void blist_end_element_handler(GMarkupParseContext *context,
795 const gchar *element_name, gpointer user_data, GError **error) {
796 if(!strcmp(element_name, "gaim")) {
797 } else if(!strcmp(element_name, "blist")) {
798 blist_parser_current_tag = BLIST_TAG_GAIM;
799 } else if(!strcmp(element_name, "group")) {
800 blist_parser_current_tag = BLIST_TAG_BLIST;
801 } else if(!strcmp(element_name, "person")) {
802 blist_parser_current_tag = BLIST_TAG_GROUP;
803 g_free(blist_parser_person_name);
804 blist_parser_person_name = NULL;
805 } else if(!strcmp(element_name, "buddy")) {
806 struct aim_user *user = find_user(blist_parser_account_name,
807 blist_parser_account_protocol);
808 if(user) {
809 struct buddy *b = add_buddy(user, blist_parser_group_name,
810 blist_parser_buddy_name, blist_parser_buddy_alias);
811 if(blist_parser_buddy_settings) {
812 g_hash_table_destroy(b->settings);
813 b->settings = blist_parser_buddy_settings;
814 }
815 }
816 blist_parser_current_tag = BLIST_TAG_PERSON;
817 g_free(blist_parser_buddy_name);
818 blist_parser_buddy_name = NULL;
819 g_free(blist_parser_buddy_alias);
820 blist_parser_buddy_alias = NULL;
821 g_free(blist_parser_account_name);
822 blist_parser_account_name = NULL;
823 blist_parser_buddy_settings = NULL;
824 } else if(!strcmp(element_name, "name")) {
825 blist_parser_current_tag = BLIST_TAG_BUDDY;
826 } else if(!strcmp(element_name, "alias")) {
827 blist_parser_current_tag = BLIST_TAG_BUDDY;
828 } else if(!strcmp(element_name, "setting")) {
829 if(!blist_parser_buddy_settings)
830 blist_parser_buddy_settings = g_hash_table_new_full(g_str_hash,
831 g_str_equal, g_free, g_free);
832 if(blist_parser_setting_name && blist_parser_setting_value) {
833 g_hash_table_replace(blist_parser_buddy_settings,
834 g_strdup(blist_parser_setting_name),
835 g_strdup(blist_parser_setting_value));
836 }
837 g_free(blist_parser_setting_name);
838 g_free(blist_parser_setting_value);
839 blist_parser_current_tag = BLIST_TAG_BUDDY;
840 } else if(!strcmp(element_name, "privacy")) {
841 blist_parser_current_tag = BLIST_TAG_GAIM;
842 } else if(!strcmp(element_name, "account")) {
843 struct aim_user *user = find_user(blist_parser_account_name,
844 blist_parser_account_protocol);
845 if(user) {
846 user->permdeny = blist_parser_privacy_mode;
847 }
848 blist_parser_current_tag = BLIST_TAG_PRIVACY;
849 g_free(blist_parser_account_name);
850 blist_parser_account_name = NULL;
851 } else if(!strcmp(element_name, "permit")) {
852 struct aim_user *user = find_user(blist_parser_account_name,
853 blist_parser_account_protocol);
854 if(user) {
855 gaim_privacy_permit_add(user, blist_parser_buddy_name);
856 }
857 blist_parser_current_tag = BLIST_TAG_ACCOUNT;
858 } else if(!strcmp(element_name, "block")) {
859 struct aim_user *user = find_user(blist_parser_account_name,
860 blist_parser_account_protocol);
861 if(user) {
862 gaim_privacy_deny_add(user, blist_parser_buddy_name);
863 }
864 blist_parser_current_tag = BLIST_TAG_ACCOUNT;
865 } else if(!strcmp(element_name, "ignore")) {
866 /* we'll apparently do something with this later */
867 blist_parser_current_tag = BLIST_TAG_ACCOUNT;
868 }
869 }
870
871 static void blist_text_handler(GMarkupParseContext *context, const gchar *text,
872 gsize text_len, gpointer user_data, GError **error) {
873 switch(blist_parser_current_tag) {
874 case BLIST_TAG_NAME:
875 blist_parser_buddy_name = g_strndup(text, text_len);
876 break;
877 case BLIST_TAG_ALIAS:
878 blist_parser_buddy_alias = g_strndup(text, text_len);
879 break;
880 case BLIST_TAG_PERMIT:
881 case BLIST_TAG_BLOCK:
882 case BLIST_TAG_IGNORE:
883 blist_parser_buddy_name = g_strndup(text, text_len);
884 break;
885 case BLIST_TAG_SETTING:
886 blist_parser_setting_value = g_strndup(text, text_len);
887 break;
888 default:
889 break;
890 }
891 }
892
893 static GMarkupParser blist_parser = {
894 blist_start_element_handler,
895 blist_end_element_handler,
896 blist_text_handler,
897 NULL,
898 NULL
899 };
900
901 static gboolean gaim_blist_read(const char *filename) {
902 gchar *contents;
903 gsize length;
904 GMarkupParseContext *context;
905 GError *error = NULL;
906 if(!g_file_get_contents(filename, &contents, &length, &error)) {
907 debug_printf("error reading blist: %s\n", error->message);
908 g_error_free(error);
909 return FALSE;
910 }
911
912 context = g_markup_parse_context_new(&blist_parser, 0, NULL, NULL);
913
914 if(!g_markup_parse_context_parse(context, contents, length, NULL)) {
915 g_markup_parse_context_free(context);
916 return FALSE;
917 }
918
919 if(!g_markup_parse_context_end_parse(context, NULL)) {
920 debug_printf("error parsing blist\n");
921 g_markup_parse_context_free(context);
922 return FALSE;
923 }
924
925 g_markup_parse_context_free(context);
926 return TRUE;
927 }
928
929 void gaim_blist_load() {
930 GSList *accts;
931 char *user_dir = gaim_user_dir();
932 char *filename;
933 char *msg;
934
935 if(!user_dir)
936 return;
937
938 filename = g_build_filename(user_dir, "blist.xml", NULL);
939
940 if(g_file_test(filename, G_FILE_TEST_EXISTS)) {
941 if(!gaim_blist_read(filename)) {
942 msg = g_strdup_printf(_("An error was encountered parsing your "
943 "buddy list. It has not been loaded."));
944 do_error_dialog(_("Buddy List Error"), msg, GAIM_ERROR);
945 g_free(msg);
946 }
947 } else {
948 /* rob wants to inform the user that their buddy lists are
949 * being converted */
950 msg = g_strdup_printf(_("Gaim is converting your old buddy lists "
951 "to a new format, which will now be located at %s"),
952 filename);
953 do_error_dialog(_("Converting Buddy List"), msg, GAIM_INFO);
954 g_free(msg);
955
956 /* now, let gtk actually display the dialog before we start anything */
957 while(gtk_events_pending())
958 gtk_main_iteration();
959
960 /* read in the old lists, then save to the new format */
961 for(accts = aim_users; accts; accts = accts->next) {
962 do_import(accts->data, NULL);
963 }
964 gaim_blist_save();
965 }
966
967 g_free(filename);
968 }
969
970 static void blist_print_buddy_settings(gpointer key, gpointer data,
971 gpointer user_data) {
972 char *key_val = g_markup_escape_text(key, -1);
973 char *data_val = g_markup_escape_text(data, -1);
974 FILE *file = user_data;
975 fprintf(file, "\t\t\t\t\t<setting name=\"%s\">%s</setting>\n", key_val,
976 data_val);
977 g_free(key_val);
978 g_free(data_val);
979 }
980
981 static void gaim_blist_write(FILE *file, struct aim_user *user) {
982 GSList *grps, *buds, *users;
983 fprintf(file, "<?xml version='1.0' encoding='UTF-8' ?>\n");
984 fprintf(file, "<gaim version=\"1\">\n");
985 fprintf(file, "\t<blist>\n");
986
987 for(grps = groups; grps; grps = grps->next) {
988 struct group *g = grps->data;
989 if(!user || gaim_group_on_account(g, user)) {
990 char *group_name = g_markup_escape_text(g->name, -1);
991 fprintf(file, "\t\t<group name=\"%s\">\n", group_name);
992 for(buds = g->members; buds; buds = buds->next) {
993 struct buddy *b = buds->data;
994 if(!user || b->user == user) {
995 char *bud_name = g_markup_escape_text(b->name, -1);
996 char *bud_alias = NULL;
997 char *acct_name = g_markup_escape_text(b->user->username, -1);
998 if(b->alias[0])
999 bud_alias= g_markup_escape_text(b->alias, -1);
1000 fprintf(file, "\t\t\t<person name=\"%s\">\n",
1001 bud_alias ? bud_alias : bud_name);
1002 fprintf(file, "\t\t\t\t<buddy protocol=\"%d\" "
1003 "account=\"%s\">\n", b->user->protocol,
1004 acct_name);
1005 fprintf(file, "\t\t\t\t\t<name>%s</name>\n", bud_name);
1006 if(bud_alias) {
1007 fprintf(file, "\t\t\t\t\t<alias>%s</alias>\n",
1008 bud_alias);
1009 }
1010 g_hash_table_foreach(b->settings,
1011 blist_print_buddy_settings, file);
1012 fprintf(file, "\t\t\t\t</buddy>\n");
1013 fprintf(file, "\t\t\t</person>\n");
1014 g_free(bud_name);
1015 g_free(bud_alias);
1016 g_free(acct_name);
1017 }
1018 }
1019 fprintf(file, "\t\t</group>\n");
1020 g_free(group_name);
1021 }
1022 }
1023
1024 fprintf(file, "\t</blist>\n");
1025 fprintf(file, "\t<privacy>\n");
1026
1027 for(users = aim_users; users; users = users->next) {
1028 struct aim_user *usr = users->data;
1029 char *acct_name = g_markup_escape_text(usr->username, -1);
1030 if(!user || usr == user) {
1031 fprintf(file, "\t\t<account protocol=\"%d\" name=\"%s\" "
1032 "mode=\"%d\">\n", usr->protocol, acct_name, usr->permdeny);
1033 for(buds = usr->permit; buds; buds = buds->next) {
1034 char *bud_name = g_markup_escape_text(buds->data, -1);
1035 fprintf(file, "\t\t\t<permit>%s</permit>\n", bud_name);
1036 g_free(bud_name);
1037 }
1038 for(buds = usr->deny; buds; buds = buds->next) {
1039 char *bud_name = g_markup_escape_text(buds->data, -1);
1040 fprintf(file, "\t\t\t<block>%s</block>\n", bud_name);
1041 g_free(bud_name);
1042 }
1043 fprintf(file, "\t\t</account>\n");
1044 }
1045 }
1046
1047 fprintf(file, "\t</privacy>\n");
1048 fprintf(file, "</gaim>\n");
1049 }
1050
1051 void gaim_blist_save() {
1052 FILE *file;
1053 char *user_dir = gaim_user_dir();
1054 char *filename;
1055
1056 if(!user_dir)
1057 return;
1058
1059 file = fopen(user_dir, "r");
1060 if(!file)
1061 mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR);
1062 else
1063 fclose(file);
1064
1065 filename = g_build_filename(user_dir, "blist.xml", NULL);
1066
1067 if((file = fopen(filename, "w"))) {
1068 gaim_blist_write(file, NULL);
1069 fclose(file);
1070 chmod(filename, S_IRUSR | S_IWUSR);
1071 } else {
1072 debug_printf("unable to write %s\n", filename);
1073 }
1074
1075 g_free(filename);
1076 }
1077
1078 gboolean gaim_privacy_permit_add(struct aim_user *user, const char *who) {
1079 GSList *d = user->permit;
1080 char *n = g_strdup(normalize(who));
1081 while(d) {
1082 if(!g_strcasecmp(n, normalize(d->data)))
1083 break;
1084 d = d->next;
1085 }
1086 g_free(n);
1087 if(!d) {
1088 user->permit = g_slist_append(user->permit, g_strdup(who));
1089 return TRUE;
1090 }
1091
1092 return FALSE;
1093 }
1094
1095 gboolean gaim_privacy_permit_remove(struct aim_user *user, const char *who) {
1096 GSList *d = user->permit;
1097 char *n = g_strdup(normalize(who));
1098 while(d) {
1099 if(!g_strcasecmp(n, normalize(d->data)))
1100 break;
1101 d = d->next;
1102 }
1103 g_free(n);
1104 if(d) {
1105 user->permit = g_slist_remove(user->permit, d->data);
1106 g_free(d->data);
1107 return TRUE;
1108 }
1109 return FALSE;
1110 }
1111
1112 gboolean gaim_privacy_deny_add(struct aim_user *user, const char *who) {
1113 GSList *d = user->deny;
1114 char *n = g_strdup(normalize(who));
1115 while(d) {
1116 if(!g_strcasecmp(n, normalize(d->data)))
1117 break;
1118 d = d->next;
1119 }
1120 g_free(n);
1121 if(!d) {
1122 user->deny = g_slist_append(user->deny, g_strdup(who));
1123 return TRUE;
1124 }
1125
1126 return FALSE;
1127 }
1128
1129 gboolean gaim_privacy_deny_remove(struct aim_user *user, const char *who) {
1130 GSList *d = user->deny;
1131 char *n = g_strdup(normalize(who));
1132 while(d) {
1133 if(!g_strcasecmp(n, normalize(d->data)))
1134 break;
1135 d = d->next;
1136 }
1137 g_free(n);
1138 if(d) {
1139 user->deny = g_slist_remove(user->deny, d->data);
1140 g_free(d->data);
1141 return TRUE;
1142 }
1143 return FALSE;
1144 }
1145
1146 void gaim_buddy_set_setting(struct buddy *b, const char *key,
1147 const char *value) {
1148 if(!b)
1149 return;
1150 g_hash_table_replace(b->settings, g_strdup(key), g_strdup(value));
1151 }
1152
1153 char *gaim_buddy_get_setting(struct buddy *b, const char *key) {
1154 if(!b)
1155 return NULL;
1156 return g_strdup(g_hash_table_lookup(b->settings, key));
1157 }