Mercurial > pidgin
annotate src/protocols/jabber/buddy.c @ 10138:5fb5c447eb4f
[gaim-migrate @ 11208]
Bring back the old smiley selection dialog for gtk<2.4 and play around
with the signals for both of them. We're not explicitly freeing the
smiley menu in gtk2.4 anymore... can someone verify that gtk is
freeing it for us? Or write a patch to free it, if not? This would
probably be a pretty big memleak if gtk isn't taking care of it...
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Mon, 25 Oct 2004 02:48:38 +0000 |
parents | a9fb4493ae22 |
children | 4e7249591251 |
rev | line source |
---|---|
7014 | 1 /* |
2 * gaim - Jabber Protocol Plugin | |
3 * | |
4 * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com> | |
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 #include "internal.h" | |
22 #include "debug.h" | |
7076 | 23 #include "imgstore.h" |
9713 | 24 #include "prpl.h" |
7014 | 25 #include "notify.h" |
26 #include "request.h" | |
27 #include "util.h" | |
7395 | 28 #include "xmlnode.h" |
7014 | 29 |
30 #include "buddy.h" | |
31 #include "chat.h" | |
32 #include "jabber.h" | |
33 #include "iq.h" | |
34 #include "presence.h" | |
35 | |
36 | |
7116 | 37 void jabber_buddy_free(JabberBuddy *jb) |
38 { | |
39 g_return_if_fail(jb != NULL); | |
40 | |
41 if(jb->error_msg) | |
42 g_free(jb->error_msg); | |
43 while(jb->resources) | |
44 jabber_buddy_resource_free(jb->resources->data); | |
45 | |
46 g_free(jb); | |
47 } | |
48 | |
7014 | 49 JabberBuddy *jabber_buddy_find(JabberStream *js, const char *name, |
50 gboolean create) | |
51 { | |
52 JabberBuddy *jb; | |
7445 | 53 const char *realname; |
7014 | 54 |
7445 | 55 if(!(realname = jabber_normalize(js->gc->account, name))) |
7014 | 56 return NULL; |
57 | |
58 jb = g_hash_table_lookup(js->buddies, realname); | |
59 | |
60 if(!jb && create) { | |
61 jb = g_new0(JabberBuddy, 1); | |
62 g_hash_table_insert(js->buddies, g_strdup(realname), jb); | |
63 } | |
64 | |
65 return jb; | |
66 } | |
67 | |
68 | |
69 JabberBuddyResource *jabber_buddy_find_resource(JabberBuddy *jb, | |
70 const char *resource) | |
71 { | |
72 JabberBuddyResource *jbr = NULL; | |
73 GList *l; | |
74 | |
75 if(!jb) | |
76 return NULL; | |
77 | |
78 for(l = jb->resources; l; l = l->next) | |
79 { | |
80 if(!jbr && !resource) { | |
81 jbr = l->data; | |
82 } else if(!resource) { | |
83 if(((JabberBuddyResource *)l->data)->priority >= jbr->priority) | |
84 jbr = l->data; | |
85 } else if(((JabberBuddyResource *)l->data)->name) { | |
86 if(!strcmp(((JabberBuddyResource *)l->data)->name, resource)) { | |
87 jbr = l->data; | |
88 break; | |
89 } | |
90 } | |
91 } | |
92 | |
93 return jbr; | |
94 } | |
95 | |
9954 | 96 JabberBuddyResource *jabber_buddy_track_resource(JabberBuddy *jb, const char *resource, |
97 int priority, JabberBuddyState state, const char *status) | |
7014 | 98 { |
99 JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, resource); | |
100 | |
101 if(!jbr) { | |
102 jbr = g_new0(JabberBuddyResource, 1); | |
7116 | 103 jbr->jb = jb; |
7014 | 104 jbr->name = g_strdup(resource); |
105 jbr->capabilities = JABBER_CAP_XHTML; | |
106 jb->resources = g_list_append(jb->resources, jbr); | |
107 } | |
108 jbr->priority = priority; | |
109 jbr->state = state; | |
110 if(jbr->status) | |
111 g_free(jbr->status); | |
112 jbr->status = g_strdup(status); | |
9954 | 113 |
114 return jbr; | |
7014 | 115 } |
116 | |
7116 | 117 void jabber_buddy_resource_free(JabberBuddyResource *jbr) |
118 { | |
119 g_return_if_fail(jbr != NULL); | |
120 | |
121 jbr->jb->resources = g_list_remove(jbr->jb->resources, jbr); | |
122 | |
123 g_free(jbr->name); | |
124 if(jbr->status) | |
125 g_free(jbr->status); | |
8400 | 126 if(jbr->thread_id) |
127 g_free(jbr->thread_id); | |
7116 | 128 g_free(jbr); |
129 } | |
130 | |
7014 | 131 void jabber_buddy_remove_resource(JabberBuddy *jb, const char *resource) |
132 { | |
133 JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, resource); | |
134 | |
135 if(!jbr) | |
136 return; | |
137 | |
7116 | 138 jabber_buddy_resource_free(jbr); |
7014 | 139 } |
140 | |
141 const char *jabber_buddy_get_status_msg(JabberBuddy *jb) | |
142 { | |
143 JabberBuddyResource *jbr; | |
144 | |
145 if(!jb) | |
146 return NULL; | |
147 | |
148 jbr = jabber_buddy_find_resource(jb, NULL); | |
149 | |
150 if(!jbr) | |
151 return NULL; | |
152 | |
153 return jbr->status; | |
154 } | |
155 | |
156 /******* | |
157 * This is the old vCard stuff taken from the old prpl. vCards, by definition | |
158 * are a temporary thing until jabber can get its act together and come up | |
159 * with a format for user information, hence the namespace of 'vcard-temp' | |
160 * | |
161 * Since I don't feel like putting that much work into something that's | |
162 * _supposed_ to go away, i'm going to just copy the kludgy old code here, | |
163 * and make it purdy when jabber comes up with a standards-track JEP to | |
164 * replace vcard-temp | |
165 * --Nathan | |
166 *******/ | |
167 | |
168 /*---------------------------------------*/ | |
169 /* Jabber "set info" (vCard) support */ | |
170 /*---------------------------------------*/ | |
171 | |
172 /* | |
173 * V-Card format: | |
174 * | |
175 * <vCard prodid='' version='' xmlns=''> | |
176 * <FN></FN> | |
177 * <N> | |
178 * <FAMILY/> | |
179 * <GIVEN/> | |
180 * </N> | |
181 * <NICKNAME/> | |
182 * <URL/> | |
183 * <ADR> | |
184 * <STREET/> | |
185 * <EXTADD/> | |
186 * <LOCALITY/> | |
187 * <REGION/> | |
188 * <PCODE/> | |
189 * <COUNTRY/> | |
190 * </ADR> | |
191 * <TEL/> | |
192 * <EMAIL/> | |
193 * <ORG> | |
194 * <ORGNAME/> | |
195 * <ORGUNIT/> | |
196 * </ORG> | |
197 * <TITLE/> | |
198 * <ROLE/> | |
199 * <DESC/> | |
200 * <BDAY/> | |
201 * </vCard> | |
202 * | |
203 * See also: | |
204 * | |
205 * http://docs.jabber.org/proto/html/vcard-temp.html | |
206 * http://www.vcard-xml.org/dtd/vCard-XML-v2-20010520.dtd | |
207 */ | |
208 | |
209 /* | |
210 * Cross-reference user-friendly V-Card entry labels to vCard XML tags | |
211 * and attributes. | |
212 * | |
213 * Order is (or should be) unimportant. For example: we have no way of | |
214 * knowing in what order real data will arrive. | |
215 * | |
216 * Format: Label, Pre-set text, "visible" flag, "editable" flag, XML tag | |
217 * name, XML tag's parent tag "path" (relative to vCard node). | |
218 * | |
219 * List is terminated by a NULL label pointer. | |
220 * | |
221 * Entries with no label text, but with XML tag and parent tag | |
222 * entries, are used by V-Card XML construction routines to | |
223 * "automagically" construct the appropriate XML node tree. | |
224 * | |
225 * Thoughts on future direction/expansion | |
226 * | |
227 * This is a "simple" vCard. | |
228 * | |
229 * It is possible for nodes other than the "vCard" node to have | |
230 * attributes. Should that prove necessary/desirable, add an | |
231 * "attributes" pointer to the vcard_template struct, create the | |
232 * necessary tag_attr structs, and add 'em to the vcard_dflt_data | |
233 * array. | |
234 * | |
235 * The above changes will (obviously) require changes to the vCard | |
236 * construction routines. | |
237 */ | |
238 | |
239 struct vcard_template { | |
240 char *label; /* label text pointer */ | |
241 char *text; /* entry text pointer */ | |
242 int visible; /* should entry field be "visible?" */ | |
243 int editable; /* should entry field be editable? */ | |
244 char *tag; /* tag text */ | |
245 char *ptag; /* parent tag "path" text */ | |
246 char *url; /* vCard display format if URL */ | |
247 } vcard_template_data[] = { | |
248 {N_("Full Name"), NULL, TRUE, TRUE, "FN", NULL, NULL}, | |
249 {N_("Family Name"), NULL, TRUE, TRUE, "FAMILY", "N", NULL}, | |
250 {N_("Given Name"), NULL, TRUE, TRUE, "GIVEN", "N", NULL}, | |
251 {N_("Nickname"), NULL, TRUE, TRUE, "NICKNAME", NULL, NULL}, | |
252 {N_("URL"), NULL, TRUE, TRUE, "URL", NULL, "<A HREF=\"%s\">%s</A>"}, | |
253 {N_("Street Address"), NULL, TRUE, TRUE, "STREET", "ADR", NULL}, | |
254 {N_("Extended Address"), NULL, TRUE, TRUE, "EXTADD", "ADR", NULL}, | |
255 {N_("Locality"), NULL, TRUE, TRUE, "LOCALITY", "ADR", NULL}, | |
256 {N_("Region"), NULL, TRUE, TRUE, "REGION", "ADR", NULL}, | |
257 {N_("Postal Code"), NULL, TRUE, TRUE, "PCODE", "ADR", NULL}, | |
258 {N_("Country"), NULL, TRUE, TRUE, "COUNTRY", "ADR", NULL}, | |
259 {N_("Telephone"), NULL, TRUE, TRUE, "TELEPHONE", NULL, NULL}, | |
260 {N_("Email"), NULL, TRUE, TRUE, "EMAIL", NULL, "<A HREF=\"mailto:%s\">%s</A>"}, | |
261 {N_("Organization Name"), NULL, TRUE, TRUE, "ORGNAME", "ORG", NULL}, | |
262 {N_("Organization Unit"), NULL, TRUE, TRUE, "ORGUNIT", "ORG", NULL}, | |
263 {N_("Title"), NULL, TRUE, TRUE, "TITLE", NULL, NULL}, | |
264 {N_("Role"), NULL, TRUE, TRUE, "ROLE", NULL, NULL}, | |
265 {N_("Birthday"), NULL, TRUE, TRUE, "BDAY", NULL, NULL}, | |
266 {N_("Description"), NULL, TRUE, TRUE, "DESC", NULL, NULL}, | |
267 {"", NULL, TRUE, TRUE, "N", NULL, NULL}, | |
268 {"", NULL, TRUE, TRUE, "ADR", NULL, NULL}, | |
269 {"", NULL, TRUE, TRUE, "ORG", NULL, NULL}, | |
270 {NULL, NULL, 0, 0, NULL, NULL, NULL} | |
271 }; | |
272 | |
273 /* | |
8735
92cbf9713795
[gaim-migrate @ 9490]
Christian Hammond <chipx86@chipx86.com>
parents:
8401
diff
changeset
|
274 * The "vCard" tag's attribute list... |
7014 | 275 */ |
276 struct tag_attr { | |
277 char *attr; | |
278 char *value; | |
279 } vcard_tag_attr_list[] = { | |
280 {"prodid", "-//HandGen//NONSGML vGen v1.0//EN"}, | |
281 {"version", "2.0", }, | |
282 {"xmlns", "vcard-temp", }, | |
283 {NULL, NULL}, | |
284 }; | |
285 | |
286 | |
287 /* | |
288 * Insert a tag node into an xmlnode tree, recursively inserting parent tag | |
289 * nodes as necessary | |
290 * | |
291 * Returns pointer to inserted node | |
292 * | |
293 * Note to hackers: this code is designed to be re-entrant (it's recursive--it | |
294 * calls itself), so don't put any "static"s in here! | |
295 */ | |
296 static xmlnode *insert_tag_to_parent_tag(xmlnode *start, const char *parent_tag, const char *new_tag) | |
297 { | |
298 xmlnode *x = NULL; | |
299 | |
300 /* | |
301 * If the parent tag wasn't specified, see if we can get it | |
302 * from the vCard template struct. | |
303 */ | |
304 if(parent_tag == NULL) { | |
305 struct vcard_template *vc_tp = vcard_template_data; | |
306 | |
307 while(vc_tp->label != NULL) { | |
308 if(strcmp(vc_tp->tag, new_tag) == 0) { | |
309 parent_tag = vc_tp->ptag; | |
310 break; | |
311 } | |
312 ++vc_tp; | |
313 } | |
314 } | |
315 | |
316 /* | |
317 * If we have a parent tag... | |
318 */ | |
319 if(parent_tag != NULL ) { | |
320 /* | |
321 * Try to get the parent node for a tag | |
322 */ | |
323 if((x = xmlnode_get_child(start, parent_tag)) == NULL) { | |
324 /* | |
325 * Descend? | |
326 */ | |
327 char *grand_parent = g_strdup(parent_tag); | |
328 char *parent; | |
329 | |
330 if((parent = strrchr(grand_parent, '/')) != NULL) { | |
331 *(parent++) = '\0'; | |
332 x = insert_tag_to_parent_tag(start, grand_parent, parent); | |
333 } else { | |
334 x = xmlnode_new_child(start, grand_parent); | |
335 } | |
336 g_free(grand_parent); | |
337 } else { | |
338 /* | |
339 * We found *something* to be the parent node. | |
340 * Note: may be the "root" node! | |
341 */ | |
342 xmlnode *y; | |
343 if((y = xmlnode_get_child(x, new_tag)) != NULL) { | |
344 return(y); | |
345 } | |
346 } | |
347 } | |
348 | |
349 /* | |
350 * insert the new tag into its parent node | |
351 */ | |
352 return(xmlnode_new_child((x == NULL? start : x), new_tag)); | |
353 } | |
354 | |
355 /* | |
356 * Send vCard info to Jabber server | |
357 */ | |
358 void jabber_set_info(GaimConnection *gc, const char *info) | |
359 { | |
360 JabberIq *iq; | |
361 JabberStream *js = gc->proto_data; | |
362 xmlnode *vc_node; | |
363 | |
364 | |
365 /* | |
366 * Send only if there's actually any *information* to send | |
367 */ | |
368 vc_node = xmlnode_from_str(info, -1); | |
369 | |
370 if(vc_node) { | |
371 if (vc_node->name && | |
372 !g_ascii_strncasecmp(vc_node->name, "vcard", 5)) { | |
373 iq = jabber_iq_new(js, JABBER_IQ_SET); | |
374 xmlnode_insert_child(iq->node, vc_node); | |
375 jabber_iq_send(iq); | |
376 } else { | |
377 xmlnode_free(vc_node); | |
378 } | |
379 } | |
380 } | |
381 | |
382 /* | |
383 * This is the callback from the "ok clicked" for "set vCard" | |
384 * | |
385 * Formats GSList data into XML-encoded string and returns a pointer | |
386 * to said string. | |
387 * | |
388 * g_free()'ing the returned string space is the responsibility of | |
389 * the caller. | |
390 */ | |
391 static void | |
392 jabber_format_info(GaimConnection *gc, GaimRequestFields *fields) | |
393 { | |
394 GaimAccount *account; | |
395 xmlnode *vc_node; | |
396 GaimRequestField *field; | |
397 const char *text; | |
398 char *p; | |
399 const struct vcard_template *vc_tp; | |
400 struct tag_attr *tag_attr; | |
401 | |
402 vc_node = xmlnode_new("vCard"); | |
403 | |
404 for(tag_attr = vcard_tag_attr_list; tag_attr->attr != NULL; ++tag_attr) | |
405 xmlnode_set_attrib(vc_node, tag_attr->attr, tag_attr->value); | |
406 | |
407 for (vc_tp = vcard_template_data; vc_tp->label != NULL; vc_tp++) { | |
408 if (*vc_tp->label == '\0') | |
409 continue; | |
410 | |
411 field = gaim_request_fields_get_field(fields, vc_tp->tag); | |
412 text = gaim_request_field_string_get_value(field); | |
413 | |
414 | |
415 if (text != NULL && *text != '\0') { | |
416 xmlnode *xp; | |
417 | |
9339 | 418 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
419 "Setting %s to '%s'\n", vc_tp->tag, text); | |
420 | |
7014 | 421 if ((xp = insert_tag_to_parent_tag(vc_node, |
422 NULL, vc_tp->tag)) != NULL) { | |
423 | |
424 xmlnode_insert_data(xp, text, -1); | |
425 } | |
426 } | |
427 } | |
428 | |
7642 | 429 p = xmlnode_to_str(vc_node, NULL); |
7014 | 430 xmlnode_free(vc_node); |
431 | |
432 account = gaim_connection_get_account(gc); | |
433 | |
434 if (account != NULL) { | |
435 gaim_account_set_user_info(account, p); | |
436 | |
437 if (gc != NULL) | |
438 serv_set_info(gc, p); | |
439 } | |
440 | |
441 g_free(p); | |
442 } | |
443 | |
444 /* | |
445 * This gets executed by the proto action | |
446 * | |
447 * Creates a new GaimRequestFields struct, gets the XML-formatted user_info | |
448 * string (if any) into GSLists for the (multi-entry) edit dialog and | |
449 * calls the set_vcard dialog. | |
450 */ | |
9015 | 451 void jabber_setup_set_info(GaimPluginAction *action) |
7014 | 452 { |
9015 | 453 GaimConnection *gc = (GaimConnection *) action->context; |
7014 | 454 GaimRequestFields *fields; |
455 GaimRequestFieldGroup *group; | |
456 GaimRequestField *field; | |
457 const struct vcard_template *vc_tp; | |
458 char *user_info; | |
459 char *cdata; | |
460 xmlnode *x_vc_data = NULL; | |
461 | |
462 fields = gaim_request_fields_new(); | |
463 group = gaim_request_field_group_new(NULL); | |
464 gaim_request_fields_add_group(fields, group); | |
465 | |
466 /* | |
467 * Get existing, XML-formatted, user info | |
468 */ | |
469 if((user_info = g_strdup(gaim_account_get_user_info(gc->account))) != NULL) | |
470 x_vc_data = xmlnode_from_str(user_info, -1); | |
471 else | |
472 user_info = g_strdup(""); | |
473 | |
474 /* | |
475 * Set up GSLists for edit with labels from "template," data from user info | |
476 */ | |
477 for(vc_tp = vcard_template_data; vc_tp->label != NULL; ++vc_tp) { | |
478 xmlnode *data_node; | |
479 if((vc_tp->label)[0] == '\0') | |
480 continue; | |
481 if(vc_tp->ptag == NULL) { | |
482 data_node = xmlnode_get_child(x_vc_data, vc_tp->tag); | |
483 } else { | |
484 gchar *tag = g_strdup_printf("%s/%s", vc_tp->ptag, vc_tp->tag); | |
485 data_node = xmlnode_get_child(x_vc_data, tag); | |
486 g_free(tag); | |
487 } | |
488 if(data_node) | |
489 cdata = xmlnode_get_data(data_node); | |
490 else | |
491 cdata = NULL; | |
492 | |
493 if(strcmp(vc_tp->tag, "DESC") == 0) { | |
494 field = gaim_request_field_string_new(vc_tp->tag, | |
495 _(vc_tp->label), cdata, | |
496 TRUE); | |
497 } else { | |
498 field = gaim_request_field_string_new(vc_tp->tag, | |
499 _(vc_tp->label), cdata, | |
500 FALSE); | |
501 } | |
502 | |
503 gaim_request_field_group_add_field(group, field); | |
504 } | |
505 | |
506 if(x_vc_data != NULL) | |
507 xmlnode_free(x_vc_data); | |
508 | |
509 g_free(user_info); | |
510 | |
511 gaim_request_fields(gc, _("Edit Jabber vCard"), | |
512 _("Edit Jabber vCard"), | |
513 _("All items below are optional. Enter only the " | |
514 "information with which you feel comfortable."), | |
515 fields, | |
516 _("Save"), G_CALLBACK(jabber_format_info), | |
517 _("Cancel"), NULL, | |
518 gc); | |
519 } | |
520 | |
521 /*---------------------------------------*/ | |
522 /* End Jabber "set info" (vCard) support */ | |
523 /*---------------------------------------*/ | |
524 | |
525 /****** | |
526 * end of that ancient crap that needs to die | |
527 ******/ | |
528 | |
529 | |
7395 | 530 static void jabber_vcard_parse(JabberStream *js, xmlnode *packet, gpointer data) |
7014 | 531 { |
532 GList *resources; | |
533 const char *from = xmlnode_get_attrib(packet, "from"); | |
534 JabberBuddy *jb; | |
535 JabberBuddyResource *jbr; | |
536 GString *info_text; | |
7306 | 537 char *resource_name; |
7955 | 538 char *bare_jid; |
7014 | 539 char *title; |
8213 | 540 char *text; |
7014 | 541 xmlnode *vcard; |
7955 | 542 GaimBuddy *b; |
7014 | 543 |
544 if(!from) | |
545 return; | |
546 | |
547 resource_name = jabber_get_resource(from); | |
7955 | 548 bare_jid = jabber_get_bare_jid(from); |
549 | |
550 b = gaim_find_buddy(js->gc->account, bare_jid); | |
7014 | 551 |
552 jb = jabber_buddy_find(js, from, TRUE); | |
553 info_text = g_string_new(""); | |
554 | |
8213 | 555 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", _("Jabber ID"), |
7014 | 556 from); |
557 | |
558 if(resource_name) { | |
559 jbr = jabber_buddy_find_resource(jb, resource_name); | |
560 if(jbr) { | |
7145 | 561 char *purdy = NULL; |
562 if(jbr->status) | |
563 purdy = gaim_strdup_withhtml(jbr->status); | |
8213 | 564 g_string_append_printf(info_text, "<b>%s:</b> %s%s%s<br/>", |
9954 | 565 _("Status"), jabber_buddy_state_get_name(jbr->state), |
7014 | 566 purdy ? ": " : "", |
567 purdy ? purdy : ""); | |
7145 | 568 if(purdy) |
569 g_free(purdy); | |
7014 | 570 } else { |
8213 | 571 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 572 _("Status"), _("Unknown")); |
573 } | |
574 } else { | |
575 for(resources = jb->resources; resources; resources = resources->next) { | |
7145 | 576 char *purdy = NULL; |
7014 | 577 jbr = resources->data; |
7145 | 578 if(jbr->status) |
579 purdy = gaim_strdup_withhtml(jbr->status); | |
8213 | 580 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 581 _("Resource"), jbr->name); |
8213 | 582 g_string_append_printf(info_text, "<b>%s:</b> %s%s%s<br/><br/>", |
9954 | 583 _("Status"), jabber_buddy_state_get_name(jbr->state), |
7014 | 584 purdy ? ": " : "", |
585 purdy ? purdy : ""); | |
7145 | 586 if(purdy) |
587 g_free(purdy); | |
7014 | 588 } |
589 } | |
590 | |
7306 | 591 g_free(resource_name); |
7955 | 592 g_free(bare_jid); |
7306 | 593 |
7014 | 594 if((vcard = xmlnode_get_child(packet, "vCard"))) { |
595 xmlnode *child; | |
596 for(child = vcard->child; child; child = child->next) | |
597 { | |
598 xmlnode *child2; | |
599 | |
8135 | 600 if(child->type != XMLNODE_TYPE_TAG) |
7014 | 601 continue; |
602 | |
603 text = xmlnode_get_data(child); | |
604 if(text && !strcmp(child->name, "FN")) { | |
8213 | 605 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 606 _("Full Name"), text); |
607 } else if(!strcmp(child->name, "N")) { | |
608 for(child2 = child->child; child2; child2 = child2->next) | |
609 { | |
610 char *text2; | |
611 | |
8135 | 612 if(child2->type != XMLNODE_TYPE_TAG) |
7014 | 613 continue; |
614 | |
615 text2 = xmlnode_get_data(child2); | |
616 if(text2 && !strcmp(child2->name, "FAMILY")) { | |
617 g_string_append_printf(info_text, | |
8213 | 618 "<b>%s:</b> %s<br/>", |
7014 | 619 _("Family Name"), text2); |
620 } else if(text2 && !strcmp(child2->name, "GIVEN")) { | |
621 g_string_append_printf(info_text, | |
8213 | 622 "<b>%s:</b> %s<br/>", |
7014 | 623 _("Given Name"), text2); |
624 } else if(text2 && !strcmp(child2->name, "MIDDLE")) { | |
625 g_string_append_printf(info_text, | |
8213 | 626 "<b>%s:</b> %s<br/>", |
7014 | 627 _("Middle Name"), text2); |
628 } | |
629 g_free(text2); | |
630 } | |
631 } else if(text && !strcmp(child->name, "NICKNAME")) { | |
632 serv_got_alias(js->gc, from, text); | |
7955 | 633 if(b) { |
634 gaim_blist_node_set_string((GaimBlistNode*)b, "servernick", text); | |
635 } | |
8213 | 636 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 637 _("Nickname"), text); |
638 } else if(text && !strcmp(child->name, "BDAY")) { | |
8213 | 639 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 640 _("Birthday"), text); |
641 } else if(!strcmp(child->name, "ADR")) { | |
642 /* show which address it is */ | |
643 if(child->child) | |
8213 | 644 g_string_append_printf(info_text, "<b>%s:</b><br/>", |
7014 | 645 _("Address")); |
646 for(child2 = child->child; child2; child2 = child2->next) | |
647 { | |
648 char *text2; | |
649 | |
8135 | 650 if(child2->type != XMLNODE_TYPE_TAG) |
7014 | 651 continue; |
652 | |
653 text2 = xmlnode_get_data(child2); | |
654 if(text2 && !strcmp(child2->name, "POBOX")) { | |
655 g_string_append_printf(info_text, | |
8213 | 656 " <b>%s:</b> %s<br/>", |
7014 | 657 _("P.O. Box"), text2); |
658 } else if(text2 && !strcmp(child2->name, "EXTADR")) { | |
659 g_string_append_printf(info_text, | |
8213 | 660 " <b>%s:</b> %s<br/>", |
7014 | 661 _("Extended Address"), text2); |
662 } else if(text2 && !strcmp(child2->name, "STREET")) { | |
663 g_string_append_printf(info_text, | |
8213 | 664 " <b>%s:</b> %s<br/>", |
7014 | 665 _("Street Address"), text2); |
666 } else if(text2 && !strcmp(child2->name, "LOCALITY")) { | |
667 g_string_append_printf(info_text, | |
8213 | 668 " <b>%s:</b> %s<br/>", |
7014 | 669 _("Locality"), text2); |
670 } else if(text2 && !strcmp(child2->name, "REGION")) { | |
671 g_string_append_printf(info_text, | |
8213 | 672 " <b>%s:</b> %s<br/>", |
7014 | 673 _("Region"), text2); |
674 } else if(text2 && !strcmp(child2->name, "PCODE")) { | |
675 g_string_append_printf(info_text, | |
8213 | 676 " <b>%s:</b> %s<br/>", |
7014 | 677 _("Postal Code"), text2); |
678 } else if(text2 && (!strcmp(child2->name, "CTRY") | |
679 || !strcmp(child2->name, "COUNTRY"))) { | |
680 g_string_append_printf(info_text, | |
8213 | 681 " <b>%s:</b> %s<br/>", |
7014 | 682 _("Country"), text2); |
683 } | |
684 g_free(text2); | |
685 } | |
686 } else if(!strcmp(child->name, "TEL")) { | |
687 char *number; | |
688 if((child2 = xmlnode_get_child(child, "NUMBER"))) { | |
689 /* show what kind of number it is */ | |
690 number = xmlnode_get_data(child2); | |
691 if(number) { | |
692 g_string_append_printf(info_text, | |
8213 | 693 "<b>%s:</b> %s<br/>", _("Telephone"), number); |
7014 | 694 g_free(number); |
695 } | |
696 } else if((number = xmlnode_get_data(child))) { | |
697 /* lots of clients (including gaim) do this, but it's | |
698 * out of spec */ | |
699 g_string_append_printf(info_text, | |
8213 | 700 "<b>%s:</b> %s<br/>", _("Telephone"), number); |
7014 | 701 g_free(number); |
702 } | |
703 } else if(!strcmp(child->name, "EMAIL")) { | |
704 char *userid; | |
705 if((child2 = xmlnode_get_child(child, "USERID"))) { | |
706 /* show what kind of email it is */ | |
707 userid = xmlnode_get_data(child2); | |
708 if(userid) { | |
709 g_string_append_printf(info_text, | |
8213 | 710 "<b>%s:</b> <a href='mailto:%s'>%s</a><br/>", |
7014 | 711 _("Email"), userid, userid); |
712 g_free(userid); | |
713 } | |
714 } else if((userid = xmlnode_get_data(child))) { | |
715 /* lots of clients (including gaim) do this, but it's | |
716 * out of spec */ | |
717 g_string_append_printf(info_text, | |
8213 | 718 "<b>%s:</b> <a href='mailto:%s'>%s</a><br/>", |
7014 | 719 _("Email"), userid, userid); |
720 g_free(userid); | |
721 } | |
722 } else if(!strcmp(child->name, "ORG")) { | |
723 for(child2 = child->child; child2; child2 = child2->next) | |
724 { | |
725 char *text2; | |
726 | |
8135 | 727 if(child2->type != XMLNODE_TYPE_TAG) |
7014 | 728 continue; |
729 | |
730 text2 = xmlnode_get_data(child2); | |
731 if(text2 && !strcmp(child2->name, "ORGNAME")) { | |
732 g_string_append_printf(info_text, | |
8213 | 733 "<b>%s:</b> %s<br/>", |
7014 | 734 _("Organization Name"), text2); |
735 } else if(text2 && !strcmp(child2->name, "ORGUNIT")) { | |
736 g_string_append_printf(info_text, | |
8213 | 737 "<b>%s:</b> %s<br/>", |
7014 | 738 _("Organization Unit"), text2); |
739 } | |
740 g_free(text2); | |
741 } | |
742 } else if(text && !strcmp(child->name, "TITLE")) { | |
8213 | 743 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 744 _("Title"), text); |
745 } else if(text && !strcmp(child->name, "ROLE")) { | |
8213 | 746 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 747 _("Role"), text); |
748 } else if(text && !strcmp(child->name, "DESC")) { | |
8213 | 749 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
750 _("Description"), text); | |
7076 | 751 } else if(!strcmp(child->name, "PHOTO") || |
752 !strcmp(child->name, "LOGO")) { | |
753 if((child2 = xmlnode_get_child(child, "BINVAL"))) { | |
754 char *data, *text2; | |
755 int size, imgid; | |
756 if((text2 = xmlnode_get_data(child2))) { | |
7106
db6bd3e794d8
[gaim-migrate @ 7671]
Christian Hammond <chipx86@chipx86.com>
parents:
7076
diff
changeset
|
757 gaim_base64_decode(text2, &data, &size); |
7076 | 758 |
759 imgid = gaim_imgstore_add(data, size, "logo.png"); | |
760 g_string_append_printf(info_text, | |
7116 | 761 "<b>%s:</b> <img id='%d'><br/>", |
7076 | 762 strcmp(child->name, "PHOTO") == 0 ? |
763 _("Photo") : _("Logo"), | |
764 imgid); | |
765 | |
766 g_free(data); | |
767 g_free(text2); | |
768 } | |
769 } | |
7014 | 770 } |
771 g_free(text); | |
772 } | |
773 } | |
774 | |
775 title = g_strdup_printf("User info for %s", from); | |
776 | |
8213 | 777 text = gaim_strdup_withhtml(info_text->str); |
778 | |
9797 | 779 gaim_notify_userinfo(js->gc, from, title, _("Jabber Profile"), |
8213 | 780 NULL, text, NULL, NULL); |
7014 | 781 |
782 g_free(title); | |
783 g_string_free(info_text, TRUE); | |
8213 | 784 g_free(text); |
7014 | 785 } |
786 | |
787 void jabber_buddy_get_info(GaimConnection *gc, const char *who) | |
788 { | |
789 JabberStream *js = gc->proto_data; | |
790 JabberIq *iq; | |
791 xmlnode *vcard; | |
792 | |
793 iq = jabber_iq_new(js, JABBER_IQ_GET); | |
794 | |
795 xmlnode_set_attrib(iq->node, "to", who); | |
796 vcard = xmlnode_new_child(iq->node, "vCard"); | |
797 xmlnode_set_attrib(vcard, "xmlns", "vcard-temp"); | |
798 | |
7395 | 799 jabber_iq_set_callback(iq, jabber_vcard_parse, NULL); |
7014 | 800 |
801 jabber_iq_send(iq); | |
802 } | |
803 | |
804 void jabber_buddy_get_info_chat(GaimConnection *gc, int id, | |
805 const char *resource) | |
806 { | |
807 JabberStream *js = gc->proto_data; | |
808 JabberChat *chat = jabber_chat_find_by_id(js, id); | |
809 char *full_jid; | |
810 | |
811 if(!chat) | |
812 return; | |
813 | |
814 full_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, resource); | |
815 jabber_buddy_get_info(gc, full_jid); | |
816 g_free(full_jid); | |
817 } | |
818 | |
7395 | 819 |
7014 | 820 static void jabber_buddy_set_invisibility(JabberStream *js, const char *who, |
821 gboolean invisible) | |
822 { | |
9944 | 823 GaimPresence *gpresence; |
824 GaimAccount *account; | |
825 GaimStatus *status; | |
7014 | 826 JabberBuddy *jb = jabber_buddy_find(js, who, TRUE); |
827 xmlnode *presence; | |
9954 | 828 JabberBuddyState state; |
829 const char *msg; | |
830 int priority; | |
7014 | 831 |
9944 | 832 account = gaim_connection_get_account(js->gc); |
833 gpresence = gaim_account_get_presence(account); | |
834 status = gaim_presence_get_active_status(gpresence); | |
835 | |
9954 | 836 gaim_status_to_jabber(status, &state, &msg, &priority); |
837 presence = jabber_presence_create(state, msg, priority); | |
838 | |
7014 | 839 xmlnode_set_attrib(presence, "to", who); |
840 if(invisible) { | |
841 xmlnode_set_attrib(presence, "type", "invisible"); | |
842 jb->invisible |= JABBER_INVIS_BUDDY; | |
843 } else { | |
844 jb->invisible &= ~JABBER_INVIS_BUDDY; | |
845 } | |
846 | |
847 jabber_send(js, presence); | |
848 xmlnode_free(presence); | |
849 } | |
850 | |
9030 | 851 static void jabber_buddy_make_invisible(GaimBlistNode *node, gpointer data) |
7014 | 852 { |
9030 | 853 GaimBuddy *buddy; |
854 GaimConnection *gc; | |
855 JabberStream *js; | |
856 | |
857 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
858 | |
859 buddy = (GaimBuddy *) node; | |
860 gc = gaim_account_get_connection(buddy->account); | |
861 js = gc->proto_data; | |
862 | |
863 jabber_buddy_set_invisibility(js, buddy->name, TRUE); | |
7014 | 864 } |
865 | |
9030 | 866 static void jabber_buddy_make_visible(GaimBlistNode *node, gpointer data) |
7014 | 867 { |
9030 | 868 GaimBuddy *buddy; |
869 GaimConnection *gc; | |
870 JabberStream *js; | |
7014 | 871 |
9030 | 872 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); |
7014 | 873 |
9030 | 874 buddy = (GaimBuddy *) node; |
875 gc = gaim_account_get_connection(buddy->account); | |
876 js = gc->proto_data; | |
877 | |
878 jabber_buddy_set_invisibility(js, buddy->name, FALSE); | |
7014 | 879 } |
880 | |
9030 | 881 static void jabber_buddy_cancel_presence_notification(GaimBlistNode *node, |
882 gpointer data) | |
7014 | 883 { |
9030 | 884 GaimBuddy *buddy; |
885 GaimConnection *gc; | |
886 JabberStream *js; | |
887 | |
888 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
7014 | 889 |
9030 | 890 buddy = (GaimBuddy *) node; |
891 gc = gaim_account_get_connection(buddy->account); | |
892 js = gc->proto_data; | |
893 | |
894 /* I wonder if we should prompt the user before doing this */ | |
895 jabber_presence_subscription_set(js, buddy->name, "unsubscribed"); | |
7014 | 896 } |
897 | |
9030 | 898 static void jabber_buddy_rerequest_auth(GaimBlistNode *node, gpointer data) |
7250 | 899 { |
9030 | 900 GaimBuddy *buddy; |
901 GaimConnection *gc; | |
902 JabberStream *js; | |
903 | |
904 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
7250 | 905 |
9030 | 906 buddy = (GaimBuddy *) node; |
907 gc = gaim_account_get_connection(buddy->account); | |
908 js = gc->proto_data; | |
909 | |
910 jabber_presence_subscription_set(js, buddy->name, "subscribe"); | |
7250 | 911 } |
912 | |
9030 | 913 |
914 static void jabber_buddy_unsubscribe(GaimBlistNode *node, gpointer data) | |
7014 | 915 { |
9030 | 916 GaimBuddy *buddy; |
917 GaimConnection *gc; | |
918 JabberStream *js; | |
919 | |
920 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
921 | |
922 buddy = (GaimBuddy *) node; | |
923 gc = gaim_account_get_connection(buddy->account); | |
924 js = gc->proto_data; | |
925 | |
926 jabber_presence_subscription_set(js, buddy->name, "unsubscribe"); | |
927 } | |
928 | |
929 | |
930 GList *jabber_buddy_menu(GaimBuddy *buddy) | |
931 { | |
932 GaimConnection *gc = gaim_account_get_connection(buddy->account); | |
933 JabberStream *js = gc->proto_data; | |
934 JabberBuddy *jb = jabber_buddy_find(js, buddy->name, TRUE); | |
935 | |
7014 | 936 GList *m = NULL; |
9030 | 937 GaimBlistNodeAction *act; |
7395 | 938 |
939 if(!jb) | |
940 return m; | |
941 | |
8185 | 942 /* XXX: fix the NOT ME below */ |
943 | |
944 if(js->protocol_version == JABBER_PROTO_0_9 /* && NOT ME */) { | |
8166 | 945 if(jb->invisible & JABBER_INVIS_BUDDY) { |
9030 | 946 act = gaim_blist_node_action_new(_("Un-hide From"), |
947 jabber_buddy_make_visible, NULL); | |
8166 | 948 } else { |
9030 | 949 act = gaim_blist_node_action_new(_("Temporarily Hide From"), |
950 jabber_buddy_make_invisible, NULL); | |
8166 | 951 } |
9030 | 952 m = g_list_append(m, act); |
7014 | 953 } |
954 | |
8185 | 955 if(jb->subscription & JABBER_SUB_FROM /* && NOT ME */) { |
9030 | 956 act = gaim_blist_node_action_new(_("Cancel Presence Notification"), |
957 jabber_buddy_cancel_presence_notification, NULL); | |
958 m = g_list_append(m, act); | |
7014 | 959 } |
960 | |
961 if(!(jb->subscription & JABBER_SUB_TO)) { | |
9030 | 962 act = gaim_blist_node_action_new(_("(Re-)Request authorization"), |
963 jabber_buddy_rerequest_auth, NULL); | |
964 m = g_list_append(m, act); | |
965 | |
8185 | 966 } else /* if(NOT ME) */{ |
9030 | 967 |
968 /* shouldn't this just happen automatically when the buddy is | |
969 removed? */ | |
970 act = gaim_blist_node_action_new(_("Unsubscribe"), | |
971 jabber_buddy_unsubscribe, NULL); | |
972 m = g_list_append(m, act); | |
7014 | 973 } |
974 | |
975 return m; | |
976 } | |
9030 | 977 |
978 GList * | |
979 jabber_blist_node_menu(GaimBlistNode *node) | |
980 { | |
981 if(GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
982 return jabber_buddy_menu((GaimBuddy *) node); | |
983 } else { | |
984 return NULL; | |
985 } | |
986 } | |
987 | |
988 | |
9954 | 989 const char * |
990 jabber_buddy_state_get_name(JabberBuddyState state) | |
991 { | |
992 switch(state) { | |
993 case JABBER_BUDDY_STATE_UNKNOWN: | |
994 return _("Unknown"); | |
995 case JABBER_BUDDY_STATE_ERROR: | |
996 return _("Error"); | |
997 case JABBER_BUDDY_STATE_UNAVAILABLE: | |
998 return _("Offline"); | |
999 case JABBER_BUDDY_STATE_ONLINE: | |
1000 return _("Online"); | |
1001 case JABBER_BUDDY_STATE_CHAT: | |
1002 return _("Chatty"); | |
1003 case JABBER_BUDDY_STATE_AWAY: | |
1004 return _("Away"); | |
1005 case JABBER_BUDDY_STATE_XA: | |
1006 return _("Extended Away"); | |
1007 case JABBER_BUDDY_STATE_DND: | |
1008 return _("Do Not Disturb"); | |
1009 } | |
1010 | |
1011 return _("Unknown"); | |
1012 } | |
1013 | |
1014 JabberBuddyState jabber_buddy_status_id_get_state(const char *id) { | |
1015 if(!id) | |
1016 return JABBER_BUDDY_STATE_UNKNOWN; | |
1017 if(!strcmp(id, "online")) | |
1018 return JABBER_BUDDY_STATE_ONLINE; | |
1019 if(!strcmp(id, "chat")) | |
1020 return JABBER_BUDDY_STATE_CHAT; | |
1021 if(!strcmp(id, "away")) | |
1022 return JABBER_BUDDY_STATE_AWAY; | |
1023 if(!strcmp(id, "xa")) | |
1024 return JABBER_BUDDY_STATE_XA; | |
1025 if(!strcmp(id, "dnd")) | |
1026 return JABBER_BUDDY_STATE_DND; | |
1027 if(!strcmp(id, "offline")) | |
1028 return JABBER_BUDDY_STATE_UNAVAILABLE; | |
1029 if(!strcmp(id, "error")) | |
1030 return JABBER_BUDDY_STATE_ERROR; | |
1031 | |
1032 return JABBER_BUDDY_STATE_UNKNOWN; | |
1033 } | |
1034 | |
1035 const char *jabber_buddy_state_get_status_id(JabberBuddyState state) { | |
1036 switch(state) { | |
1037 case JABBER_BUDDY_STATE_CHAT: | |
1038 return "chat"; | |
1039 case JABBER_BUDDY_STATE_AWAY: | |
1040 return "away"; | |
1041 case JABBER_BUDDY_STATE_XA: | |
1042 return "xa"; | |
1043 case JABBER_BUDDY_STATE_DND: | |
1044 return "dnd"; | |
1045 case JABBER_BUDDY_STATE_ONLINE: | |
1046 return "online"; | |
1047 case JABBER_BUDDY_STATE_UNKNOWN: | |
1048 case JABBER_BUDDY_STATE_ERROR: | |
1049 return NULL; | |
1050 case JABBER_BUDDY_STATE_UNAVAILABLE: | |
1051 return "offline"; | |
1052 } | |
1053 return NULL; | |
1054 } |