Mercurial > pidgin
annotate src/protocols/jabber/buddy.c @ 14067:f3ed5f4efcae
[gaim-migrate @ 16688]
Fix for CID 110 (which also will fix some asserts that happen when you edit your Jabber User Info for the first time)
Fix for CID 251 (Null check after deref)
Fixes for CID 252, 253. (UNUSED_VALUE)
I also changed the jabber_buddy_find() call in jabber_vcard_parse not to create the JabberBuddy if it doesn't exist - there should be a specific jabber buddy attached to the JabberBuddyInfo and if isn't present any more, we shouldn't create a new one.
committer: Tailor Script <tailor@pidgin.im>
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Thu, 10 Aug 2006 21:08:00 +0000 |
parents | 25e63008d3bb |
children | 6cb8bdc3366f |
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" | |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10662
diff
changeset
|
22 #include "cipher.h" |
7014 | 23 #include "debug.h" |
7076 | 24 #include "imgstore.h" |
9713 | 25 #include "prpl.h" |
7014 | 26 #include "notify.h" |
27 #include "request.h" | |
28 #include "util.h" | |
7395 | 29 #include "xmlnode.h" |
7014 | 30 |
31 #include "buddy.h" | |
32 #include "chat.h" | |
33 #include "jabber.h" | |
34 #include "iq.h" | |
35 #include "presence.h" | |
11675 | 36 #include "xdata.h" |
7014 | 37 |
13792 | 38 typedef struct { |
39 long idle_seconds; | |
40 } JabberBuddyInfoResource; | |
41 | |
42 typedef struct { | |
43 JabberStream *js; | |
44 JabberBuddy *jb; | |
45 char *jid; | |
46 GSList *ids; | |
47 GHashTable *resources; | |
48 int timeout_handle; | |
49 char *vcard_text; | |
50 GSList *vcard_imgids; | |
51 } JabberBuddyInfo; | |
52 | |
7116 | 53 void jabber_buddy_free(JabberBuddy *jb) |
54 { | |
55 g_return_if_fail(jb != NULL); | |
56 | |
57 if(jb->error_msg) | |
58 g_free(jb->error_msg); | |
59 while(jb->resources) | |
60 jabber_buddy_resource_free(jb->resources->data); | |
61 | |
62 g_free(jb); | |
63 } | |
64 | |
7014 | 65 JabberBuddy *jabber_buddy_find(JabberStream *js, const char *name, |
66 gboolean create) | |
67 { | |
68 JabberBuddy *jb; | |
7445 | 69 const char *realname; |
7014 | 70 |
7445 | 71 if(!(realname = jabber_normalize(js->gc->account, name))) |
7014 | 72 return NULL; |
73 | |
74 jb = g_hash_table_lookup(js->buddies, realname); | |
75 | |
76 if(!jb && create) { | |
77 jb = g_new0(JabberBuddy, 1); | |
78 g_hash_table_insert(js->buddies, g_strdup(realname), jb); | |
79 } | |
80 | |
81 return jb; | |
82 } | |
83 | |
84 | |
85 JabberBuddyResource *jabber_buddy_find_resource(JabberBuddy *jb, | |
86 const char *resource) | |
87 { | |
88 JabberBuddyResource *jbr = NULL; | |
89 GList *l; | |
90 | |
91 if(!jb) | |
92 return NULL; | |
93 | |
94 for(l = jb->resources; l; l = l->next) | |
95 { | |
96 if(!jbr && !resource) { | |
97 jbr = l->data; | |
98 } else if(!resource) { | |
99 if(((JabberBuddyResource *)l->data)->priority >= jbr->priority) | |
100 jbr = l->data; | |
101 } else if(((JabberBuddyResource *)l->data)->name) { | |
102 if(!strcmp(((JabberBuddyResource *)l->data)->name, resource)) { | |
103 jbr = l->data; | |
104 break; | |
105 } | |
106 } | |
107 } | |
108 | |
109 return jbr; | |
110 } | |
111 | |
9954 | 112 JabberBuddyResource *jabber_buddy_track_resource(JabberBuddy *jb, const char *resource, |
113 int priority, JabberBuddyState state, const char *status) | |
7014 | 114 { |
115 JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, resource); | |
116 | |
117 if(!jbr) { | |
118 jbr = g_new0(JabberBuddyResource, 1); | |
7116 | 119 jbr->jb = jb; |
7014 | 120 jbr->name = g_strdup(resource); |
121 jbr->capabilities = JABBER_CAP_XHTML; | |
122 jb->resources = g_list_append(jb->resources, jbr); | |
123 } | |
124 jbr->priority = priority; | |
125 jbr->state = state; | |
126 if(jbr->status) | |
127 g_free(jbr->status); | |
13785 | 128 if (status) |
129 jbr->status = g_markup_escape_text(status, -1); | |
130 else | |
131 jbr->status = NULL; | |
9954 | 132 |
133 return jbr; | |
7014 | 134 } |
135 | |
7116 | 136 void jabber_buddy_resource_free(JabberBuddyResource *jbr) |
137 { | |
138 g_return_if_fail(jbr != NULL); | |
139 | |
140 jbr->jb->resources = g_list_remove(jbr->jb->resources, jbr); | |
141 | |
142 g_free(jbr->name); | |
13792 | 143 g_free(jbr->status); |
144 g_free(jbr->thread_id); | |
145 g_free(jbr->client.name); | |
146 g_free(jbr->client.version); | |
147 g_free(jbr->client.os); | |
7116 | 148 g_free(jbr); |
149 } | |
150 | |
7014 | 151 void jabber_buddy_remove_resource(JabberBuddy *jb, const char *resource) |
152 { | |
153 JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, resource); | |
154 | |
155 if(!jbr) | |
156 return; | |
157 | |
7116 | 158 jabber_buddy_resource_free(jbr); |
7014 | 159 } |
160 | |
161 const char *jabber_buddy_get_status_msg(JabberBuddy *jb) | |
162 { | |
163 JabberBuddyResource *jbr; | |
164 | |
165 if(!jb) | |
166 return NULL; | |
167 | |
168 jbr = jabber_buddy_find_resource(jb, NULL); | |
169 | |
170 if(!jbr) | |
171 return NULL; | |
172 | |
173 return jbr->status; | |
174 } | |
175 | |
176 /******* | |
177 * This is the old vCard stuff taken from the old prpl. vCards, by definition | |
178 * are a temporary thing until jabber can get its act together and come up | |
179 * with a format for user information, hence the namespace of 'vcard-temp' | |
180 * | |
181 * Since I don't feel like putting that much work into something that's | |
182 * _supposed_ to go away, i'm going to just copy the kludgy old code here, | |
183 * and make it purdy when jabber comes up with a standards-track JEP to | |
184 * replace vcard-temp | |
185 * --Nathan | |
186 *******/ | |
187 | |
188 /*---------------------------------------*/ | |
189 /* Jabber "set info" (vCard) support */ | |
190 /*---------------------------------------*/ | |
191 | |
192 /* | |
193 * V-Card format: | |
194 * | |
195 * <vCard prodid='' version='' xmlns=''> | |
196 * <FN></FN> | |
197 * <N> | |
198 * <FAMILY/> | |
199 * <GIVEN/> | |
200 * </N> | |
201 * <NICKNAME/> | |
202 * <URL/> | |
203 * <ADR> | |
204 * <STREET/> | |
205 * <EXTADD/> | |
206 * <LOCALITY/> | |
207 * <REGION/> | |
208 * <PCODE/> | |
209 * <COUNTRY/> | |
210 * </ADR> | |
211 * <TEL/> | |
212 * <EMAIL/> | |
213 * <ORG> | |
214 * <ORGNAME/> | |
215 * <ORGUNIT/> | |
216 * </ORG> | |
217 * <TITLE/> | |
218 * <ROLE/> | |
219 * <DESC/> | |
220 * <BDAY/> | |
221 * </vCard> | |
222 * | |
223 * See also: | |
224 * | |
225 * http://docs.jabber.org/proto/html/vcard-temp.html | |
226 * http://www.vcard-xml.org/dtd/vCard-XML-v2-20010520.dtd | |
227 */ | |
228 | |
229 /* | |
230 * Cross-reference user-friendly V-Card entry labels to vCard XML tags | |
231 * and attributes. | |
232 * | |
233 * Order is (or should be) unimportant. For example: we have no way of | |
234 * knowing in what order real data will arrive. | |
235 * | |
236 * Format: Label, Pre-set text, "visible" flag, "editable" flag, XML tag | |
237 * name, XML tag's parent tag "path" (relative to vCard node). | |
238 * | |
239 * List is terminated by a NULL label pointer. | |
240 * | |
241 * Entries with no label text, but with XML tag and parent tag | |
242 * entries, are used by V-Card XML construction routines to | |
243 * "automagically" construct the appropriate XML node tree. | |
244 * | |
245 * Thoughts on future direction/expansion | |
246 * | |
247 * This is a "simple" vCard. | |
248 * | |
249 * It is possible for nodes other than the "vCard" node to have | |
250 * attributes. Should that prove necessary/desirable, add an | |
251 * "attributes" pointer to the vcard_template struct, create the | |
252 * necessary tag_attr structs, and add 'em to the vcard_dflt_data | |
253 * array. | |
254 * | |
255 * The above changes will (obviously) require changes to the vCard | |
256 * construction routines. | |
257 */ | |
258 | |
259 struct vcard_template { | |
260 char *label; /* label text pointer */ | |
261 char *text; /* entry text pointer */ | |
262 int visible; /* should entry field be "visible?" */ | |
263 int editable; /* should entry field be editable? */ | |
264 char *tag; /* tag text */ | |
265 char *ptag; /* parent tag "path" text */ | |
266 char *url; /* vCard display format if URL */ | |
267 } vcard_template_data[] = { | |
268 {N_("Full Name"), NULL, TRUE, TRUE, "FN", NULL, NULL}, | |
269 {N_("Family Name"), NULL, TRUE, TRUE, "FAMILY", "N", NULL}, | |
270 {N_("Given Name"), NULL, TRUE, TRUE, "GIVEN", "N", NULL}, | |
271 {N_("Nickname"), NULL, TRUE, TRUE, "NICKNAME", NULL, NULL}, | |
272 {N_("URL"), NULL, TRUE, TRUE, "URL", NULL, "<A HREF=\"%s\">%s</A>"}, | |
273 {N_("Street Address"), NULL, TRUE, TRUE, "STREET", "ADR", NULL}, | |
274 {N_("Extended Address"), NULL, TRUE, TRUE, "EXTADD", "ADR", NULL}, | |
275 {N_("Locality"), NULL, TRUE, TRUE, "LOCALITY", "ADR", NULL}, | |
276 {N_("Region"), NULL, TRUE, TRUE, "REGION", "ADR", NULL}, | |
277 {N_("Postal Code"), NULL, TRUE, TRUE, "PCODE", "ADR", NULL}, | |
13331 | 278 {N_("Country"), NULL, TRUE, TRUE, "CTRY", "ADR", NULL}, |
11361 | 279 {N_("Telephone"), NULL, TRUE, TRUE, "NUMBER", "TEL", NULL}, |
13545
cfc2f7fcb3dd
[gaim-migrate @ 15922]
Richard Laager <rlaager@wiktel.com>
parents:
13344
diff
changeset
|
280 {N_("E-Mail"), NULL, TRUE, TRUE, "USERID", "EMAIL", "<A HREF=\"mailto:%s\">%s</A>"}, |
7014 | 281 {N_("Organization Name"), NULL, TRUE, TRUE, "ORGNAME", "ORG", NULL}, |
282 {N_("Organization Unit"), NULL, TRUE, TRUE, "ORGUNIT", "ORG", NULL}, | |
283 {N_("Title"), NULL, TRUE, TRUE, "TITLE", NULL, NULL}, | |
284 {N_("Role"), NULL, TRUE, TRUE, "ROLE", NULL, NULL}, | |
285 {N_("Birthday"), NULL, TRUE, TRUE, "BDAY", NULL, NULL}, | |
286 {N_("Description"), NULL, TRUE, TRUE, "DESC", NULL, NULL}, | |
287 {"", NULL, TRUE, TRUE, "N", NULL, NULL}, | |
288 {"", NULL, TRUE, TRUE, "ADR", NULL, NULL}, | |
289 {"", NULL, TRUE, TRUE, "ORG", NULL, NULL}, | |
290 {NULL, NULL, 0, 0, NULL, NULL, NULL} | |
291 }; | |
292 | |
293 /* | |
8735
92cbf9713795
[gaim-migrate @ 9490]
Christian Hammond <chipx86@chipx86.com>
parents:
8401
diff
changeset
|
294 * The "vCard" tag's attribute list... |
7014 | 295 */ |
296 struct tag_attr { | |
297 char *attr; | |
298 char *value; | |
299 } vcard_tag_attr_list[] = { | |
300 {"prodid", "-//HandGen//NONSGML vGen v1.0//EN"}, | |
301 {"version", "2.0", }, | |
302 {"xmlns", "vcard-temp", }, | |
303 {NULL, NULL}, | |
304 }; | |
305 | |
306 | |
307 /* | |
308 * Insert a tag node into an xmlnode tree, recursively inserting parent tag | |
309 * nodes as necessary | |
310 * | |
311 * Returns pointer to inserted node | |
312 * | |
313 * Note to hackers: this code is designed to be re-entrant (it's recursive--it | |
314 * calls itself), so don't put any "static"s in here! | |
315 */ | |
316 static xmlnode *insert_tag_to_parent_tag(xmlnode *start, const char *parent_tag, const char *new_tag) | |
317 { | |
318 xmlnode *x = NULL; | |
319 | |
320 /* | |
321 * If the parent tag wasn't specified, see if we can get it | |
322 * from the vCard template struct. | |
323 */ | |
324 if(parent_tag == NULL) { | |
325 struct vcard_template *vc_tp = vcard_template_data; | |
326 | |
327 while(vc_tp->label != NULL) { | |
328 if(strcmp(vc_tp->tag, new_tag) == 0) { | |
329 parent_tag = vc_tp->ptag; | |
330 break; | |
331 } | |
332 ++vc_tp; | |
333 } | |
334 } | |
335 | |
336 /* | |
337 * If we have a parent tag... | |
338 */ | |
339 if(parent_tag != NULL ) { | |
340 /* | |
341 * Try to get the parent node for a tag | |
342 */ | |
343 if((x = xmlnode_get_child(start, parent_tag)) == NULL) { | |
344 /* | |
345 * Descend? | |
346 */ | |
347 char *grand_parent = g_strdup(parent_tag); | |
348 char *parent; | |
349 | |
350 if((parent = strrchr(grand_parent, '/')) != NULL) { | |
351 *(parent++) = '\0'; | |
352 x = insert_tag_to_parent_tag(start, grand_parent, parent); | |
353 } else { | |
354 x = xmlnode_new_child(start, grand_parent); | |
355 } | |
356 g_free(grand_parent); | |
357 } else { | |
358 /* | |
359 * We found *something* to be the parent node. | |
360 * Note: may be the "root" node! | |
361 */ | |
362 xmlnode *y; | |
363 if((y = xmlnode_get_child(x, new_tag)) != NULL) { | |
364 return(y); | |
365 } | |
366 } | |
367 } | |
368 | |
369 /* | |
370 * insert the new tag into its parent node | |
371 */ | |
372 return(xmlnode_new_child((x == NULL? start : x), new_tag)); | |
373 } | |
374 | |
375 /* | |
376 * Send vCard info to Jabber server | |
377 */ | |
378 void jabber_set_info(GaimConnection *gc, const char *info) | |
379 { | |
380 JabberIq *iq; | |
381 JabberStream *js = gc->proto_data; | |
382 xmlnode *vc_node; | |
11303
10066662176a
[gaim-migrate @ 13503]
Richard Laager <rlaager@wiktel.com>
parents:
11183
diff
changeset
|
383 char *avatar_file = NULL; |
13691
87b027bb1f15
[gaim-migrate @ 16094]
Richard Laager <rlaager@wiktel.com>
parents:
13640
diff
changeset
|
384 struct tag_attr *tag_attr; |
7014 | 385 |
10189 | 386 if(js->avatar_hash) |
387 g_free(js->avatar_hash); | |
388 js->avatar_hash = NULL; | |
7014 | 389 |
390 /* | |
391 * Send only if there's actually any *information* to send | |
392 */ | |
11388 | 393 vc_node = info ? xmlnode_from_str(info, -1) : NULL; |
11318 | 394 avatar_file = gaim_buddy_icons_get_full_path(gaim_account_get_buddy_icon(gc->account)); |
10189 | 395 |
396 if(!vc_node && avatar_file) { | |
397 vc_node = xmlnode_new("vCard"); | |
13691
87b027bb1f15
[gaim-migrate @ 16094]
Richard Laager <rlaager@wiktel.com>
parents:
13640
diff
changeset
|
398 for(tag_attr = vcard_tag_attr_list; tag_attr->attr != NULL; ++tag_attr) |
87b027bb1f15
[gaim-migrate @ 16094]
Richard Laager <rlaager@wiktel.com>
parents:
13640
diff
changeset
|
399 xmlnode_set_attrib(vc_node, tag_attr->attr, tag_attr->value); |
10189 | 400 } |
7014 | 401 |
402 if(vc_node) { | |
403 if (vc_node->name && | |
10189 | 404 !g_ascii_strncasecmp(vc_node->name, "vCard", 5)) { |
405 GError *error = NULL; | |
11509 | 406 gchar *avatar_data_tmp; |
407 guchar *avatar_data; | |
10189 | 408 gsize avatar_len; |
409 | |
11509 | 410 if(avatar_file && g_file_get_contents(avatar_file, &avatar_data_tmp, &avatar_len, &error)) { |
10941 | 411 xmlnode *photo, *binval; |
11127 | 412 gchar *enc; |
10189 | 413 int i; |
414 unsigned char hashval[20]; | |
415 char *p, hash[41]; | |
416 | |
11521 | 417 avatar_data = (guchar *) avatar_data_tmp; |
10189 | 418 photo = xmlnode_new_child(vc_node, "PHOTO"); |
10941 | 419 binval = xmlnode_new_child(photo, "BINVAL"); |
10189 | 420 enc = gaim_base64_encode(avatar_data, avatar_len); |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10662
diff
changeset
|
421 |
11183 | 422 gaim_cipher_digest_region("sha1", (guchar *)avatar_data, |
10687
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
423 avatar_len, sizeof(hashval), |
b256ce6b85b8
[gaim-migrate @ 12235]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10684
diff
changeset
|
424 hashval, NULL); |
10684
72a5babfa8b4
[gaim-migrate @ 12231]
Luke Schierer <lschiere@pidgin.im>
parents:
10662
diff
changeset
|
425 |
10189 | 426 p = hash; |
427 for(i=0; i<20; i++, p+=2) | |
428 snprintf(p, 3, "%02x", hashval[i]); | |
429 js->avatar_hash = g_strdup(hash); | |
430 | |
10941 | 431 xmlnode_insert_data(binval, enc, -1); |
10189 | 432 g_free(enc); |
433 g_free(avatar_data); | |
10504 | 434 } else if (error != NULL) { |
10189 | 435 g_error_free(error); |
436 } | |
11303
10066662176a
[gaim-migrate @ 13503]
Richard Laager <rlaager@wiktel.com>
parents:
11183
diff
changeset
|
437 g_free(avatar_file); |
10189 | 438 |
7014 | 439 iq = jabber_iq_new(js, JABBER_IQ_SET); |
440 xmlnode_insert_child(iq->node, vc_node); | |
441 jabber_iq_send(iq); | |
442 } else { | |
443 xmlnode_free(vc_node); | |
444 } | |
445 } | |
446 } | |
447 | |
10189 | 448 void jabber_set_buddy_icon(GaimConnection *gc, const char *iconfile) |
449 { | |
450 GaimPresence *gpresence; | |
451 GaimStatus *status; | |
452 | |
453 jabber_set_info(gc, gaim_account_get_user_info(gc->account)); | |
454 | |
455 gpresence = gaim_account_get_presence(gc->account); | |
456 status = gaim_presence_get_active_status(gpresence); | |
10216 | 457 jabber_presence_send(gc->account, status); |
10189 | 458 } |
459 | |
7014 | 460 /* |
461 * This is the callback from the "ok clicked" for "set vCard" | |
462 * | |
463 * Formats GSList data into XML-encoded string and returns a pointer | |
464 * to said string. | |
465 * | |
466 * g_free()'ing the returned string space is the responsibility of | |
467 * the caller. | |
468 */ | |
469 static void | |
470 jabber_format_info(GaimConnection *gc, GaimRequestFields *fields) | |
471 { | |
472 xmlnode *vc_node; | |
473 GaimRequestField *field; | |
474 const char *text; | |
475 char *p; | |
476 const struct vcard_template *vc_tp; | |
477 struct tag_attr *tag_attr; | |
478 | |
479 vc_node = xmlnode_new("vCard"); | |
480 | |
481 for(tag_attr = vcard_tag_attr_list; tag_attr->attr != NULL; ++tag_attr) | |
482 xmlnode_set_attrib(vc_node, tag_attr->attr, tag_attr->value); | |
483 | |
484 for (vc_tp = vcard_template_data; vc_tp->label != NULL; vc_tp++) { | |
485 if (*vc_tp->label == '\0') | |
486 continue; | |
487 | |
488 field = gaim_request_fields_get_field(fields, vc_tp->tag); | |
489 text = gaim_request_field_string_get_value(field); | |
490 | |
491 | |
492 if (text != NULL && *text != '\0') { | |
493 xmlnode *xp; | |
494 | |
9339 | 495 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
496 "Setting %s to '%s'\n", vc_tp->tag, text); | |
497 | |
7014 | 498 if ((xp = insert_tag_to_parent_tag(vc_node, |
499 NULL, vc_tp->tag)) != NULL) { | |
500 | |
501 xmlnode_insert_data(xp, text, -1); | |
502 } | |
503 } | |
504 } | |
505 | |
7642 | 506 p = xmlnode_to_str(vc_node, NULL); |
7014 | 507 xmlnode_free(vc_node); |
508 | |
13713
2cf94cdb2e99
[gaim-migrate @ 16117]
Richard Laager <rlaager@wiktel.com>
parents:
13691
diff
changeset
|
509 if (gc != NULL) { |
2cf94cdb2e99
[gaim-migrate @ 16117]
Richard Laager <rlaager@wiktel.com>
parents:
13691
diff
changeset
|
510 GaimAccount *account = gaim_connection_get_account(gc); |
7014 | 511 |
13713
2cf94cdb2e99
[gaim-migrate @ 16117]
Richard Laager <rlaager@wiktel.com>
parents:
13691
diff
changeset
|
512 if (account != NULL) { |
2cf94cdb2e99
[gaim-migrate @ 16117]
Richard Laager <rlaager@wiktel.com>
parents:
13691
diff
changeset
|
513 gaim_account_set_user_info(account, p); |
7014 | 514 serv_set_info(gc, p); |
13713
2cf94cdb2e99
[gaim-migrate @ 16117]
Richard Laager <rlaager@wiktel.com>
parents:
13691
diff
changeset
|
515 } |
7014 | 516 } |
517 | |
518 g_free(p); | |
519 } | |
520 | |
521 /* | |
522 * This gets executed by the proto action | |
523 * | |
524 * Creates a new GaimRequestFields struct, gets the XML-formatted user_info | |
525 * string (if any) into GSLists for the (multi-entry) edit dialog and | |
526 * calls the set_vcard dialog. | |
527 */ | |
9015 | 528 void jabber_setup_set_info(GaimPluginAction *action) |
7014 | 529 { |
9015 | 530 GaimConnection *gc = (GaimConnection *) action->context; |
7014 | 531 GaimRequestFields *fields; |
532 GaimRequestFieldGroup *group; | |
533 GaimRequestField *field; | |
534 const struct vcard_template *vc_tp; | |
14067
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
535 const char *user_info; |
7014 | 536 char *cdata; |
537 xmlnode *x_vc_data = NULL; | |
538 | |
539 fields = gaim_request_fields_new(); | |
540 group = gaim_request_field_group_new(NULL); | |
541 gaim_request_fields_add_group(fields, group); | |
542 | |
543 /* | |
544 * Get existing, XML-formatted, user info | |
545 */ | |
14067
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
546 if((user_info = gaim_account_get_user_info(gc->account)) != NULL) |
7014 | 547 x_vc_data = xmlnode_from_str(user_info, -1); |
548 | |
549 /* | |
550 * Set up GSLists for edit with labels from "template," data from user info | |
551 */ | |
552 for(vc_tp = vcard_template_data; vc_tp->label != NULL; ++vc_tp) { | |
553 xmlnode *data_node; | |
554 if((vc_tp->label)[0] == '\0') | |
555 continue; | |
14067
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
556 |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
557 if (x_vc_data != NULL) { |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
558 if(vc_tp->ptag == NULL) { |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
559 data_node = xmlnode_get_child(x_vc_data, vc_tp->tag); |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
560 } else { |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
561 gchar *tag = g_strdup_printf("%s/%s", vc_tp->ptag, vc_tp->tag); |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
562 data_node = xmlnode_get_child(x_vc_data, tag); |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
563 g_free(tag); |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
564 } |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
565 if(data_node) |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
566 cdata = xmlnode_get_data(data_node); |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
567 else |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
568 cdata = NULL; |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
569 } else |
7014 | 570 cdata = NULL; |
571 | |
572 if(strcmp(vc_tp->tag, "DESC") == 0) { | |
573 field = gaim_request_field_string_new(vc_tp->tag, | |
574 _(vc_tp->label), cdata, | |
575 TRUE); | |
576 } else { | |
577 field = gaim_request_field_string_new(vc_tp->tag, | |
578 _(vc_tp->label), cdata, | |
579 FALSE); | |
580 } | |
581 | |
582 gaim_request_field_group_add_field(group, field); | |
583 } | |
584 | |
585 if(x_vc_data != NULL) | |
586 xmlnode_free(x_vc_data); | |
587 | |
588 gaim_request_fields(gc, _("Edit Jabber vCard"), | |
589 _("Edit Jabber vCard"), | |
590 _("All items below are optional. Enter only the " | |
591 "information with which you feel comfortable."), | |
592 fields, | |
593 _("Save"), G_CALLBACK(jabber_format_info), | |
594 _("Cancel"), NULL, | |
595 gc); | |
596 } | |
597 | |
598 /*---------------------------------------*/ | |
599 /* End Jabber "set info" (vCard) support */ | |
600 /*---------------------------------------*/ | |
601 | |
602 /****** | |
603 * end of that ancient crap that needs to die | |
604 ******/ | |
605 | |
13792 | 606 static void jabber_buddy_info_show_if_ready(JabberBuddyInfo *jbi) |
7014 | 607 { |
608 GString *info_text; | |
7306 | 609 char *resource_name; |
13792 | 610 JabberBuddyResource *jbr; |
611 JabberBuddyInfoResource *jbir; | |
612 GList *resources; | |
7014 | 613 |
13792 | 614 /* not yet */ |
615 if(jbi->ids) | |
11361 | 616 return; |
617 | |
7014 | 618 info_text = g_string_new(""); |
13792 | 619 resource_name = jabber_get_resource(jbi->jid); |
7014 | 620 |
621 if(resource_name) { | |
13792 | 622 jbr = jabber_buddy_find_resource(jbi->jb, resource_name); |
623 jbir = g_hash_table_lookup(jbi->resources, resource_name); | |
7014 | 624 if(jbr) { |
7145 | 625 char *purdy = NULL; |
626 if(jbr->status) | |
627 purdy = gaim_strdup_withhtml(jbr->status); | |
8213 | 628 g_string_append_printf(info_text, "<b>%s:</b> %s%s%s<br/>", |
9954 | 629 _("Status"), jabber_buddy_state_get_name(jbr->state), |
7014 | 630 purdy ? ": " : "", |
631 purdy ? purdy : ""); | |
7145 | 632 if(purdy) |
633 g_free(purdy); | |
7014 | 634 } else { |
8213 | 635 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 636 _("Status"), _("Unknown")); |
637 } | |
13792 | 638 if(jbir) { |
639 if(jbir->idle_seconds > 0) { | |
640 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", | |
641 _("Idle"), gaim_str_seconds_to_string(jbir->idle_seconds)); | |
642 } | |
643 } | |
644 if(jbr && jbr->client.name) { | |
645 g_string_append_printf(info_text, "<b>%s:</b> %s %s<br/>", | |
646 _("Client:"), jbr->client.name, | |
647 jbr->client.version ? jbr->client.version : ""); | |
648 if(jbr->client.os) { | |
649 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", | |
650 _("Operating System"), jbr->client.os); | |
651 } | |
652 } | |
7014 | 653 } else { |
13792 | 654 for(resources = jbi->jb->resources; resources; resources = resources->next) { |
7145 | 655 char *purdy = NULL; |
7014 | 656 jbr = resources->data; |
7145 | 657 if(jbr->status) |
658 purdy = gaim_strdup_withhtml(jbr->status); | |
8213 | 659 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 660 _("Resource"), jbr->name); |
13792 | 661 g_string_append_printf(info_text, "<b>%s:</b> %s%s%s<br/>", |
9954 | 662 _("Status"), jabber_buddy_state_get_name(jbr->state), |
7014 | 663 purdy ? ": " : "", |
664 purdy ? purdy : ""); | |
7145 | 665 if(purdy) |
666 g_free(purdy); | |
13792 | 667 |
668 jbir = g_hash_table_lookup(jbi->resources, jbr->name); | |
669 if(jbir) { | |
670 if(jbir->idle_seconds > 0) { | |
671 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", | |
672 _("Idle"), gaim_str_seconds_to_string(jbir->idle_seconds)); | |
673 } | |
674 } | |
675 if(jbr->client.name) { | |
676 g_string_append_printf(info_text, "<b>%s:</b> %s %s<br/>", | |
677 _("Client:"), jbr->client.name, | |
678 jbr->client.version ? jbr->client.version : ""); | |
679 if(jbr->client.os) { | |
680 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", | |
681 _("Operating System"), jbr->client.os); | |
682 } | |
683 } | |
684 | |
685 g_string_append_printf(info_text, "<br/>"); | |
7014 | 686 } |
687 } | |
688 | |
7306 | 689 g_free(resource_name); |
690 | |
13792 | 691 info_text = g_string_append(info_text, jbi->vcard_text); |
692 | |
693 gaim_notify_userinfo(jbi->js->gc, jbi->jid, info_text->str, NULL, NULL); | |
694 | |
695 while(jbi->vcard_imgids) { | |
696 gaim_imgstore_unref(GPOINTER_TO_INT(jbi->vcard_imgids->data)); | |
697 jbi->vcard_imgids = g_slist_delete_link(jbi->vcard_imgids, jbi->vcard_imgids); | |
698 } | |
699 | |
700 g_string_free(info_text, TRUE); | |
701 | |
702 gaim_timeout_remove(jbi->timeout_handle); | |
703 g_free(jbi->jid); | |
704 g_hash_table_destroy(jbi->resources); | |
705 g_free(jbi->vcard_text); | |
706 g_free(jbi); | |
707 } | |
708 | |
709 static void jabber_buddy_info_remove_id(JabberBuddyInfo *jbi, const char *id) | |
710 { | |
711 GSList *l = jbi->ids; | |
712 | |
713 if(!id) | |
714 return; | |
715 | |
716 while(l) { | |
717 if(!strcmp(id, l->data)) { | |
718 jbi->ids = g_slist_remove(jbi->ids, l->data); | |
719 return; | |
720 } | |
721 l = l->next; | |
722 } | |
723 } | |
724 | |
725 static void jabber_vcard_parse(JabberStream *js, xmlnode *packet, gpointer data) | |
726 { | |
14067
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
727 const char *id, *from; |
13792 | 728 GString *info_text; |
729 char *bare_jid; | |
730 char *text; | |
731 xmlnode *vcard; | |
732 GaimBuddy *b; | |
733 JabberBuddyInfo *jbi = data; | |
734 | |
735 from = xmlnode_get_attrib(packet, "from"); | |
736 id = xmlnode_get_attrib(packet, "id"); | |
737 | |
738 if(!jbi) | |
739 return; | |
740 | |
14067
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
741 jabber_buddy_info_remove_id(jbi, id); |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
742 |
13792 | 743 if(!from) |
744 return; | |
745 | |
14067
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
746 if(!jabber_buddy_find(js, from, FALSE)) |
13792 | 747 return; |
748 | |
749 /* XXX: handle the error case */ | |
750 | |
751 bare_jid = jabber_get_bare_jid(from); | |
752 | |
753 b = gaim_find_buddy(js->gc->account, bare_jid); | |
754 | |
755 info_text = g_string_new(""); | |
756 | |
10189 | 757 if((vcard = xmlnode_get_child(packet, "vCard")) || |
758 (vcard = xmlnode_get_child_with_namespace(packet, "query", "vcard-temp"))) { | |
7014 | 759 xmlnode *child; |
760 for(child = vcard->child; child; child = child->next) | |
761 { | |
762 xmlnode *child2; | |
763 | |
8135 | 764 if(child->type != XMLNODE_TYPE_TAG) |
7014 | 765 continue; |
766 | |
767 text = xmlnode_get_data(child); | |
768 if(text && !strcmp(child->name, "FN")) { | |
8213 | 769 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 770 _("Full Name"), text); |
771 } else if(!strcmp(child->name, "N")) { | |
772 for(child2 = child->child; child2; child2 = child2->next) | |
773 { | |
774 char *text2; | |
775 | |
8135 | 776 if(child2->type != XMLNODE_TYPE_TAG) |
7014 | 777 continue; |
778 | |
779 text2 = xmlnode_get_data(child2); | |
780 if(text2 && !strcmp(child2->name, "FAMILY")) { | |
781 g_string_append_printf(info_text, | |
8213 | 782 "<b>%s:</b> %s<br/>", |
7014 | 783 _("Family Name"), text2); |
784 } else if(text2 && !strcmp(child2->name, "GIVEN")) { | |
785 g_string_append_printf(info_text, | |
8213 | 786 "<b>%s:</b> %s<br/>", |
7014 | 787 _("Given Name"), text2); |
788 } else if(text2 && !strcmp(child2->name, "MIDDLE")) { | |
789 g_string_append_printf(info_text, | |
8213 | 790 "<b>%s:</b> %s<br/>", |
7014 | 791 _("Middle Name"), text2); |
792 } | |
793 g_free(text2); | |
794 } | |
795 } else if(text && !strcmp(child->name, "NICKNAME")) { | |
796 serv_got_alias(js->gc, from, text); | |
7955 | 797 if(b) { |
798 gaim_blist_node_set_string((GaimBlistNode*)b, "servernick", text); | |
799 } | |
8213 | 800 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 801 _("Nickname"), text); |
802 } else if(text && !strcmp(child->name, "BDAY")) { | |
8213 | 803 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 804 _("Birthday"), text); |
805 } else if(!strcmp(child->name, "ADR")) { | |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
806 gboolean address_line_added = FALSE; |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
807 |
7014 | 808 for(child2 = child->child; child2; child2 = child2->next) |
809 { | |
810 char *text2; | |
811 | |
8135 | 812 if(child2->type != XMLNODE_TYPE_TAG) |
7014 | 813 continue; |
814 | |
815 text2 = xmlnode_get_data(child2); | |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
816 if (text2 == NULL) |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
817 continue; |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
818 |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
819 /* We do this here so that it's not added if all the child |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
820 * elements are empty. */ |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
821 if (!address_line_added) |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
822 { |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
823 g_string_append_printf(info_text, "<b>%s:</b><br/>", |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
824 _("Address")); |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
825 address_line_added = TRUE; |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
826 } |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
827 |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
828 if(!strcmp(child2->name, "POBOX")) { |
7014 | 829 g_string_append_printf(info_text, |
8213 | 830 " <b>%s:</b> %s<br/>", |
7014 | 831 _("P.O. Box"), text2); |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
832 } else if(!strcmp(child2->name, "EXTADR")) { |
7014 | 833 g_string_append_printf(info_text, |
8213 | 834 " <b>%s:</b> %s<br/>", |
7014 | 835 _("Extended Address"), text2); |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
836 } else if(!strcmp(child2->name, "STREET")) { |
7014 | 837 g_string_append_printf(info_text, |
8213 | 838 " <b>%s:</b> %s<br/>", |
7014 | 839 _("Street Address"), text2); |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
840 } else if(!strcmp(child2->name, "LOCALITY")) { |
7014 | 841 g_string_append_printf(info_text, |
8213 | 842 " <b>%s:</b> %s<br/>", |
7014 | 843 _("Locality"), text2); |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
844 } else if(!strcmp(child2->name, "REGION")) { |
7014 | 845 g_string_append_printf(info_text, |
8213 | 846 " <b>%s:</b> %s<br/>", |
7014 | 847 _("Region"), text2); |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
848 } else if(!strcmp(child2->name, "PCODE")) { |
7014 | 849 g_string_append_printf(info_text, |
8213 | 850 " <b>%s:</b> %s<br/>", |
7014 | 851 _("Postal Code"), text2); |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
852 } else if(!strcmp(child2->name, "CTRY") |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
853 || !strcmp(child2->name, "COUNTRY")) { |
7014 | 854 g_string_append_printf(info_text, |
8213 | 855 " <b>%s:</b> %s<br/>", |
7014 | 856 _("Country"), text2); |
857 } | |
858 g_free(text2); | |
859 } | |
860 } else if(!strcmp(child->name, "TEL")) { | |
861 char *number; | |
862 if((child2 = xmlnode_get_child(child, "NUMBER"))) { | |
863 /* show what kind of number it is */ | |
864 number = xmlnode_get_data(child2); | |
865 if(number) { | |
866 g_string_append_printf(info_text, | |
8213 | 867 "<b>%s:</b> %s<br/>", _("Telephone"), number); |
7014 | 868 g_free(number); |
869 } | |
870 } else if((number = xmlnode_get_data(child))) { | |
871 /* lots of clients (including gaim) do this, but it's | |
872 * out of spec */ | |
873 g_string_append_printf(info_text, | |
8213 | 874 "<b>%s:</b> %s<br/>", _("Telephone"), number); |
7014 | 875 g_free(number); |
876 } | |
877 } else if(!strcmp(child->name, "EMAIL")) { | |
878 char *userid; | |
879 if((child2 = xmlnode_get_child(child, "USERID"))) { | |
880 /* show what kind of email it is */ | |
881 userid = xmlnode_get_data(child2); | |
882 if(userid) { | |
883 g_string_append_printf(info_text, | |
8213 | 884 "<b>%s:</b> <a href='mailto:%s'>%s</a><br/>", |
13545
cfc2f7fcb3dd
[gaim-migrate @ 15922]
Richard Laager <rlaager@wiktel.com>
parents:
13344
diff
changeset
|
885 _("E-Mail"), userid, userid); |
7014 | 886 g_free(userid); |
887 } | |
888 } else if((userid = xmlnode_get_data(child))) { | |
889 /* lots of clients (including gaim) do this, but it's | |
890 * out of spec */ | |
891 g_string_append_printf(info_text, | |
8213 | 892 "<b>%s:</b> <a href='mailto:%s'>%s</a><br/>", |
13545
cfc2f7fcb3dd
[gaim-migrate @ 15922]
Richard Laager <rlaager@wiktel.com>
parents:
13344
diff
changeset
|
893 _("E-Mail"), userid, userid); |
7014 | 894 g_free(userid); |
895 } | |
896 } else if(!strcmp(child->name, "ORG")) { | |
897 for(child2 = child->child; child2; child2 = child2->next) | |
898 { | |
899 char *text2; | |
900 | |
8135 | 901 if(child2->type != XMLNODE_TYPE_TAG) |
7014 | 902 continue; |
903 | |
904 text2 = xmlnode_get_data(child2); | |
905 if(text2 && !strcmp(child2->name, "ORGNAME")) { | |
906 g_string_append_printf(info_text, | |
8213 | 907 "<b>%s:</b> %s<br/>", |
7014 | 908 _("Organization Name"), text2); |
909 } else if(text2 && !strcmp(child2->name, "ORGUNIT")) { | |
910 g_string_append_printf(info_text, | |
8213 | 911 "<b>%s:</b> %s<br/>", |
7014 | 912 _("Organization Unit"), text2); |
913 } | |
914 g_free(text2); | |
915 } | |
916 } else if(text && !strcmp(child->name, "TITLE")) { | |
8213 | 917 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 918 _("Title"), text); |
919 } else if(text && !strcmp(child->name, "ROLE")) { | |
8213 | 920 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 921 _("Role"), text); |
922 } else if(text && !strcmp(child->name, "DESC")) { | |
8213 | 923 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
924 _("Description"), text); | |
7076 | 925 } else if(!strcmp(child->name, "PHOTO") || |
926 !strcmp(child->name, "LOGO")) { | |
10941 | 927 char *bintext = NULL; |
928 xmlnode *binval; | |
11361 | 929 |
930 if( ((binval = xmlnode_get_child(child, "BINVAL")) && | |
931 (bintext = xmlnode_get_data(binval))) || | |
932 (bintext = xmlnode_get_data(child))) { | |
11127 | 933 gsize size; |
11137 | 934 guchar *data; |
11127 | 935 int i; |
10941 | 936 unsigned char hashval[20]; |
11127 | 937 char *p, hash[41]; |
10941 | 938 gboolean photo = (strcmp(child->name, "PHOTO") == 0); |
10189 | 939 |
11361 | 940 data = gaim_base64_decode(bintext, &size); |
7076 | 941 |
13792 | 942 jbi->vcard_imgids = g_slist_prepend(jbi->vcard_imgids, GINT_TO_POINTER(gaim_imgstore_add(data, size, "logo.png"))); |
10941 | 943 g_string_append_printf(info_text, |
944 "<b>%s:</b> <img id='%d'><br/>", | |
945 photo ? _("Photo") : _("Logo"), | |
13792 | 946 GPOINTER_TO_INT(jbi->vcard_imgids->data)); |
7076 | 947 |
10941 | 948 gaim_buddy_icons_set_for_user(js->gc->account, bare_jid, |
949 data, size); | |
10189 | 950 |
11183 | 951 gaim_cipher_digest_region("sha1", (guchar *)data, size, |
10941 | 952 sizeof(hashval), hashval, NULL); |
953 p = hash; | |
954 for(i=0; i<20; i++, p+=2) | |
955 snprintf(p, 3, "%02x", hashval[i]); | |
956 gaim_blist_node_set_string((GaimBlistNode*)b, "avatar_hash", hash); | |
10189 | 957 |
10941 | 958 g_free(data); |
959 g_free(bintext); | |
960 } | |
7014 | 961 } |
962 g_free(text); | |
963 } | |
964 } | |
965 | |
13792 | 966 jbi->vcard_text = gaim_strdup_withhtml(info_text->str); |
967 g_string_free(info_text, TRUE); | |
968 g_free(bare_jid); | |
969 | |
970 jabber_buddy_info_show_if_ready(jbi); | |
971 } | |
972 | |
8213 | 973 |
13792 | 974 static void jabber_buddy_info_resource_free(gpointer data) |
975 { | |
976 JabberBuddyInfoResource *jbri = data; | |
977 g_free(jbri); | |
978 } | |
979 | |
980 static void jabber_version_parse(JabberStream *js, xmlnode *packet, gpointer data) | |
981 { | |
982 JabberBuddyInfo *jbi = data; | |
983 const char *type, *id, *from; | |
984 xmlnode *query; | |
985 char *resource_name; | |
986 | |
987 g_return_if_fail(jbi != NULL); | |
988 | |
989 type = xmlnode_get_attrib(packet, "type"); | |
990 id = xmlnode_get_attrib(packet, "id"); | |
991 from = xmlnode_get_attrib(packet, "from"); | |
7014 | 992 |
13792 | 993 jabber_buddy_info_remove_id(jbi, id); |
994 | |
995 if(!from) | |
996 return; | |
997 | |
998 resource_name = jabber_get_resource(from); | |
999 | |
1000 if(resource_name) { | |
1001 if(type && !strcmp(type, "result")) { | |
1002 if((query = xmlnode_get_child(packet, "query"))) { | |
1003 JabberBuddyResource *jbr = jabber_buddy_find_resource(jbi->jb, resource_name); | |
1004 if(jbr) { | |
1005 xmlnode *node; | |
1006 if((node = xmlnode_get_child(query, "name"))) { | |
1007 jbr->client.name = xmlnode_get_data(node); | |
1008 } | |
1009 if((node = xmlnode_get_child(query, "version"))) { | |
1010 jbr->client.version = xmlnode_get_data(node); | |
1011 } | |
1012 if((node = xmlnode_get_child(query, "os"))) { | |
1013 jbr->client.os = xmlnode_get_data(node); | |
1014 } | |
1015 } | |
1016 } | |
1017 } | |
1018 g_free(resource_name); | |
10189 | 1019 } |
13792 | 1020 |
1021 jabber_buddy_info_show_if_ready(jbi); | |
7014 | 1022 } |
1023 | |
13792 | 1024 static void jabber_last_parse(JabberStream *js, xmlnode *packet, gpointer data) |
1025 { | |
1026 JabberBuddyInfo *jbi = data; | |
1027 xmlnode *query; | |
1028 char *resource_name; | |
1029 const char *type, *id, *from, *seconds; | |
1030 | |
1031 g_return_if_fail(jbi != NULL); | |
1032 | |
1033 type = xmlnode_get_attrib(packet, "type"); | |
1034 id = xmlnode_get_attrib(packet, "id"); | |
1035 from = xmlnode_get_attrib(packet, "from"); | |
1036 | |
1037 jabber_buddy_info_remove_id(jbi, id); | |
1038 | |
1039 if(!from) | |
1040 return; | |
1041 | |
1042 resource_name = jabber_get_resource(from); | |
1043 | |
1044 if(resource_name) { | |
1045 if(type && !strcmp(type, "result")) { | |
1046 if((query = xmlnode_get_child(packet, "query"))) { | |
1047 seconds = xmlnode_get_attrib(query, "seconds"); | |
1048 if(seconds) { | |
1049 char *end = NULL; | |
1050 long sec = strtol(seconds, &end, 10); | |
1051 if(end != seconds) { | |
1052 JabberBuddyInfoResource *jbir = g_hash_table_lookup(jbi->resources, resource_name); | |
1053 if(jbir) { | |
1054 jbir->idle_seconds = sec; | |
1055 } | |
1056 } | |
1057 } | |
1058 } | |
1059 } | |
1060 g_free(resource_name); | |
1061 } | |
1062 | |
1063 jabber_buddy_info_show_if_ready(jbi); | |
1064 } | |
1065 | |
1066 static gboolean jabber_buddy_get_info_timeout(gpointer data) | |
1067 { | |
1068 JabberBuddyInfo *jbi = data; | |
1069 | |
1070 /* remove the pending callbacks */ | |
1071 while(jbi->ids) { | |
1072 char *id = jbi->ids->data; | |
1073 jabber_iq_remove_callback_by_id(jbi->js, id); | |
1074 g_free(id); | |
1075 jbi->ids = g_slist_remove(jbi->ids, id); | |
1076 } | |
1077 | |
1078 jbi->timeout_handle = 0; | |
1079 | |
1080 jabber_buddy_info_show_if_ready(jbi); | |
1081 | |
1082 return FALSE; | |
1083 } | |
1084 | |
1085 static void jabber_buddy_get_info_for_jid(JabberStream *js, const char *jid) | |
7014 | 1086 { |
1087 JabberIq *iq; | |
1088 xmlnode *vcard; | |
13792 | 1089 GList *resources; |
1090 JabberBuddy *jb; | |
1091 JabberBuddyInfo *jbi; | |
1092 | |
1093 jb = jabber_buddy_find(js, jid, TRUE); | |
1094 | |
1095 /* invalid JID */ | |
1096 if(!jb) | |
1097 return; | |
1098 | |
1099 jbi = g_new0(JabberBuddyInfo, 1); | |
1100 jbi->jid = g_strdup(jid); | |
1101 jbi->js = js; | |
1102 jbi->jb = jb; | |
1103 jbi->resources = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, jabber_buddy_info_resource_free); | |
7014 | 1104 |
1105 iq = jabber_iq_new(js, JABBER_IQ_GET); | |
1106 | |
13792 | 1107 xmlnode_set_attrib(iq->node, "to", jid); |
7014 | 1108 vcard = xmlnode_new_child(iq->node, "vCard"); |
13806 | 1109 xmlnode_set_namespace(vcard, "vcard-temp"); |
7014 | 1110 |
13792 | 1111 jabber_iq_set_callback(iq, jabber_vcard_parse, jbi); |
1112 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id)); | |
7014 | 1113 |
1114 jabber_iq_send(iq); | |
13792 | 1115 |
1116 for(resources = jb->resources; resources; resources = resources->next) | |
1117 { | |
1118 JabberBuddyResource *jbr = resources->data; | |
1119 JabberBuddyInfoResource *jbir = g_new0(JabberBuddyInfoResource, 1); | |
1120 char *full_jid; | |
1121 if(strrchr(jid, '/')) { | |
1122 full_jid = g_strdup(jid); | |
1123 } else { | |
1124 full_jid = g_strdup_printf("%s/%s", jid, jbr->name); | |
1125 } | |
1126 | |
1127 g_hash_table_insert(jbi->resources, g_strdup(jbr->name), jbir); | |
1128 | |
1129 if(!jbr->client.name) { | |
1130 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:version"); | |
1131 xmlnode_set_attrib(iq->node, "to", full_jid); | |
1132 jabber_iq_set_callback(iq, jabber_version_parse, jbi); | |
1133 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id)); | |
1134 jabber_iq_send(iq); | |
1135 } | |
1136 | |
1137 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:last"); | |
1138 xmlnode_set_attrib(iq->node, "to", full_jid); | |
1139 jabber_iq_set_callback(iq, jabber_last_parse, jbi); | |
1140 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id)); | |
1141 jabber_iq_send(iq); | |
1142 | |
1143 g_free(full_jid); | |
1144 } | |
1145 | |
1146 jbi->timeout_handle = gaim_timeout_add(30000, jabber_buddy_get_info_timeout, jbi); | |
7014 | 1147 } |
1148 | |
10189 | 1149 void jabber_buddy_get_info(GaimConnection *gc, const char *who) |
1150 { | |
1151 JabberStream *js = gc->proto_data; | |
1152 char *bare_jid = jabber_get_bare_jid(who); | |
1153 | |
1154 if(bare_jid) { | |
1155 jabber_buddy_get_info_for_jid(js, bare_jid); | |
1156 g_free(bare_jid); | |
1157 } | |
1158 } | |
1159 | |
7014 | 1160 void jabber_buddy_get_info_chat(GaimConnection *gc, int id, |
1161 const char *resource) | |
1162 { | |
1163 JabberStream *js = gc->proto_data; | |
1164 JabberChat *chat = jabber_chat_find_by_id(js, id); | |
1165 char *full_jid; | |
1166 | |
1167 if(!chat) | |
1168 return; | |
1169 | |
1170 full_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, resource); | |
10189 | 1171 jabber_buddy_get_info_for_jid(js, full_jid); |
7014 | 1172 g_free(full_jid); |
1173 } | |
1174 | |
7395 | 1175 |
7014 | 1176 static void jabber_buddy_set_invisibility(JabberStream *js, const char *who, |
1177 gboolean invisible) | |
1178 { | |
9944 | 1179 GaimPresence *gpresence; |
1180 GaimAccount *account; | |
1181 GaimStatus *status; | |
7014 | 1182 JabberBuddy *jb = jabber_buddy_find(js, who, TRUE); |
1183 xmlnode *presence; | |
9954 | 1184 JabberBuddyState state; |
1185 const char *msg; | |
1186 int priority; | |
7014 | 1187 |
9944 | 1188 account = gaim_connection_get_account(js->gc); |
1189 gpresence = gaim_account_get_presence(account); | |
1190 status = gaim_presence_get_active_status(gpresence); | |
1191 | |
9954 | 1192 gaim_status_to_jabber(status, &state, &msg, &priority); |
1193 presence = jabber_presence_create(state, msg, priority); | |
1194 | |
7014 | 1195 xmlnode_set_attrib(presence, "to", who); |
1196 if(invisible) { | |
1197 xmlnode_set_attrib(presence, "type", "invisible"); | |
1198 jb->invisible |= JABBER_INVIS_BUDDY; | |
1199 } else { | |
1200 jb->invisible &= ~JABBER_INVIS_BUDDY; | |
1201 } | |
1202 | |
1203 jabber_send(js, presence); | |
1204 xmlnode_free(presence); | |
1205 } | |
1206 | |
9030 | 1207 static void jabber_buddy_make_invisible(GaimBlistNode *node, gpointer data) |
7014 | 1208 { |
9030 | 1209 GaimBuddy *buddy; |
1210 GaimConnection *gc; | |
1211 JabberStream *js; | |
1212 | |
1213 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
1214 | |
1215 buddy = (GaimBuddy *) node; | |
1216 gc = gaim_account_get_connection(buddy->account); | |
1217 js = gc->proto_data; | |
1218 | |
1219 jabber_buddy_set_invisibility(js, buddy->name, TRUE); | |
7014 | 1220 } |
1221 | |
9030 | 1222 static void jabber_buddy_make_visible(GaimBlistNode *node, gpointer data) |
7014 | 1223 { |
9030 | 1224 GaimBuddy *buddy; |
1225 GaimConnection *gc; | |
1226 JabberStream *js; | |
7014 | 1227 |
9030 | 1228 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); |
7014 | 1229 |
9030 | 1230 buddy = (GaimBuddy *) node; |
1231 gc = gaim_account_get_connection(buddy->account); | |
1232 js = gc->proto_data; | |
1233 | |
1234 jabber_buddy_set_invisibility(js, buddy->name, FALSE); | |
7014 | 1235 } |
1236 | |
9030 | 1237 static void jabber_buddy_cancel_presence_notification(GaimBlistNode *node, |
1238 gpointer data) | |
7014 | 1239 { |
9030 | 1240 GaimBuddy *buddy; |
1241 GaimConnection *gc; | |
1242 JabberStream *js; | |
1243 | |
1244 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
7014 | 1245 |
9030 | 1246 buddy = (GaimBuddy *) node; |
1247 gc = gaim_account_get_connection(buddy->account); | |
1248 js = gc->proto_data; | |
1249 | |
1250 /* I wonder if we should prompt the user before doing this */ | |
1251 jabber_presence_subscription_set(js, buddy->name, "unsubscribed"); | |
7014 | 1252 } |
1253 | |
9030 | 1254 static void jabber_buddy_rerequest_auth(GaimBlistNode *node, gpointer data) |
7250 | 1255 { |
9030 | 1256 GaimBuddy *buddy; |
1257 GaimConnection *gc; | |
1258 JabberStream *js; | |
1259 | |
1260 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
7250 | 1261 |
9030 | 1262 buddy = (GaimBuddy *) node; |
1263 gc = gaim_account_get_connection(buddy->account); | |
1264 js = gc->proto_data; | |
1265 | |
1266 jabber_presence_subscription_set(js, buddy->name, "subscribe"); | |
7250 | 1267 } |
1268 | |
9030 | 1269 |
1270 static void jabber_buddy_unsubscribe(GaimBlistNode *node, gpointer data) | |
7014 | 1271 { |
9030 | 1272 GaimBuddy *buddy; |
1273 GaimConnection *gc; | |
1274 JabberStream *js; | |
1275 | |
1276 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
1277 | |
1278 buddy = (GaimBuddy *) node; | |
1279 gc = gaim_account_get_connection(buddy->account); | |
1280 js = gc->proto_data; | |
1281 | |
1282 jabber_presence_subscription_set(js, buddy->name, "unsubscribe"); | |
1283 } | |
1284 | |
1285 | |
12323
fc464a0abccc
[gaim-migrate @ 14627]
Richard Laager <rlaager@wiktel.com>
parents:
12284
diff
changeset
|
1286 static GList *jabber_buddy_menu(GaimBuddy *buddy) |
9030 | 1287 { |
1288 GaimConnection *gc = gaim_account_get_connection(buddy->account); | |
1289 JabberStream *js = gc->proto_data; | |
1290 JabberBuddy *jb = jabber_buddy_find(js, buddy->name, TRUE); | |
1291 | |
7014 | 1292 GList *m = NULL; |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1293 GaimMenuAction *act; |
7395 | 1294 |
1295 if(!jb) | |
1296 return m; | |
1297 | |
8185 | 1298 /* XXX: fix the NOT ME below */ |
1299 | |
1300 if(js->protocol_version == JABBER_PROTO_0_9 /* && NOT ME */) { | |
8166 | 1301 if(jb->invisible & JABBER_INVIS_BUDDY) { |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1302 act = gaim_menu_action_new(_("Un-hide From"), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1303 GAIM_CALLBACK(jabber_buddy_make_visible), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1304 NULL, NULL); |
8166 | 1305 } else { |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1306 act = gaim_menu_action_new(_("Temporarily Hide From"), |
13019
8504ce176d38
[gaim-migrate @ 15372]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12933
diff
changeset
|
1307 GAIM_CALLBACK(jabber_buddy_make_invisible), |
8504ce176d38
[gaim-migrate @ 15372]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12933
diff
changeset
|
1308 NULL, NULL); |
8166 | 1309 } |
9030 | 1310 m = g_list_append(m, act); |
7014 | 1311 } |
1312 | |
8185 | 1313 if(jb->subscription & JABBER_SUB_FROM /* && NOT ME */) { |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1314 act = gaim_menu_action_new(_("Cancel Presence Notification"), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1315 GAIM_CALLBACK(jabber_buddy_cancel_presence_notification), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1316 NULL, NULL); |
9030 | 1317 m = g_list_append(m, act); |
7014 | 1318 } |
1319 | |
1320 if(!(jb->subscription & JABBER_SUB_TO)) { | |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1321 act = gaim_menu_action_new(_("(Re-)Request authorization"), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1322 GAIM_CALLBACK(jabber_buddy_rerequest_auth), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1323 NULL, NULL); |
9030 | 1324 m = g_list_append(m, act); |
1325 | |
8185 | 1326 } else /* if(NOT ME) */{ |
9030 | 1327 |
1328 /* shouldn't this just happen automatically when the buddy is | |
1329 removed? */ | |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1330 act = gaim_menu_action_new(_("Unsubscribe"), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1331 GAIM_CALLBACK(jabber_buddy_unsubscribe), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1332 NULL, NULL); |
9030 | 1333 m = g_list_append(m, act); |
7014 | 1334 } |
1335 | |
1336 return m; | |
1337 } | |
9030 | 1338 |
1339 GList * | |
1340 jabber_blist_node_menu(GaimBlistNode *node) | |
1341 { | |
1342 if(GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
1343 return jabber_buddy_menu((GaimBuddy *) node); | |
1344 } else { | |
1345 return NULL; | |
1346 } | |
1347 } | |
1348 | |
1349 | |
9954 | 1350 const char * |
1351 jabber_buddy_state_get_name(JabberBuddyState state) | |
1352 { | |
1353 switch(state) { | |
1354 case JABBER_BUDDY_STATE_UNKNOWN: | |
1355 return _("Unknown"); | |
1356 case JABBER_BUDDY_STATE_ERROR: | |
1357 return _("Error"); | |
1358 case JABBER_BUDDY_STATE_UNAVAILABLE: | |
1359 return _("Offline"); | |
1360 case JABBER_BUDDY_STATE_ONLINE: | |
12467
1b57012eec7b
[gaim-migrate @ 14777]
Richard Laager <rlaager@wiktel.com>
parents:
12323
diff
changeset
|
1361 return _("Available"); |
9954 | 1362 case JABBER_BUDDY_STATE_CHAT: |
1363 return _("Chatty"); | |
1364 case JABBER_BUDDY_STATE_AWAY: | |
1365 return _("Away"); | |
1366 case JABBER_BUDDY_STATE_XA: | |
1367 return _("Extended Away"); | |
1368 case JABBER_BUDDY_STATE_DND: | |
1369 return _("Do Not Disturb"); | |
1370 } | |
1371 | |
1372 return _("Unknown"); | |
1373 } | |
1374 | |
1375 JabberBuddyState jabber_buddy_status_id_get_state(const char *id) { | |
1376 if(!id) | |
1377 return JABBER_BUDDY_STATE_UNKNOWN; | |
11540 | 1378 if(!strcmp(id, "available")) |
9954 | 1379 return JABBER_BUDDY_STATE_ONLINE; |
12683 | 1380 if(!strcmp(id, "freeforchat")) |
1381 return JABBER_BUDDY_STATE_CHAT; | |
1382 if(!strcmp(id, "away")) | |
1383 return JABBER_BUDDY_STATE_AWAY; | |
1384 if(!strcmp(id, "extended_away")) | |
1385 return JABBER_BUDDY_STATE_XA; | |
1386 if(!strcmp(id, "dnd")) | |
1387 return JABBER_BUDDY_STATE_DND; | |
1388 if(!strcmp(id, "offline")) | |
1389 return JABBER_BUDDY_STATE_UNAVAILABLE; | |
1390 if(!strcmp(id, "error")) | |
1391 return JABBER_BUDDY_STATE_ERROR; | |
1392 | |
1393 return JABBER_BUDDY_STATE_UNKNOWN; | |
1394 } | |
1395 | |
1396 JabberBuddyState jabber_buddy_show_get_state(const char *id) { | |
1397 if(!id) | |
1398 return JABBER_BUDDY_STATE_UNKNOWN; | |
1399 if(!strcmp(id, "available")) | |
1400 return JABBER_BUDDY_STATE_ONLINE; | |
9954 | 1401 if(!strcmp(id, "chat")) |
1402 return JABBER_BUDDY_STATE_CHAT; | |
1403 if(!strcmp(id, "away")) | |
1404 return JABBER_BUDDY_STATE_AWAY; | |
1405 if(!strcmp(id, "xa")) | |
1406 return JABBER_BUDDY_STATE_XA; | |
1407 if(!strcmp(id, "dnd")) | |
1408 return JABBER_BUDDY_STATE_DND; | |
1409 if(!strcmp(id, "offline")) | |
1410 return JABBER_BUDDY_STATE_UNAVAILABLE; | |
1411 if(!strcmp(id, "error")) | |
1412 return JABBER_BUDDY_STATE_ERROR; | |
1413 | |
1414 return JABBER_BUDDY_STATE_UNKNOWN; | |
1415 } | |
1416 | |
12683 | 1417 const char *jabber_buddy_state_get_show(JabberBuddyState state) { |
9954 | 1418 switch(state) { |
1419 case JABBER_BUDDY_STATE_CHAT: | |
1420 return "chat"; | |
1421 case JABBER_BUDDY_STATE_AWAY: | |
1422 return "away"; | |
1423 case JABBER_BUDDY_STATE_XA: | |
1424 return "xa"; | |
1425 case JABBER_BUDDY_STATE_DND: | |
1426 return "dnd"; | |
1427 case JABBER_BUDDY_STATE_ONLINE: | |
11540 | 1428 return "available"; |
9954 | 1429 case JABBER_BUDDY_STATE_UNKNOWN: |
1430 case JABBER_BUDDY_STATE_ERROR: | |
1431 return NULL; | |
1432 case JABBER_BUDDY_STATE_UNAVAILABLE: | |
1433 return "offline"; | |
1434 } | |
1435 return NULL; | |
1436 } | |
11675 | 1437 |
12683 | 1438 const char *jabber_buddy_state_get_status_id(JabberBuddyState state) { |
1439 switch(state) { | |
1440 case JABBER_BUDDY_STATE_CHAT: | |
1441 return "freeforchat"; | |
1442 case JABBER_BUDDY_STATE_AWAY: | |
1443 return "away"; | |
1444 case JABBER_BUDDY_STATE_XA: | |
1445 return "extended_away"; | |
1446 case JABBER_BUDDY_STATE_DND: | |
1447 return "dnd"; | |
1448 case JABBER_BUDDY_STATE_ONLINE: | |
1449 return "available"; | |
1450 case JABBER_BUDDY_STATE_UNKNOWN: | |
13756 | 1451 return "available"; |
12683 | 1452 case JABBER_BUDDY_STATE_ERROR: |
13756 | 1453 return "error"; |
12683 | 1454 case JABBER_BUDDY_STATE_UNAVAILABLE: |
1455 return "offline"; | |
1456 } | |
1457 return NULL; | |
1458 } | |
1459 | |
13640 | 1460 static void user_search_result_add_buddy_cb(GaimConnection *gc, GList *row, void *user_data) |
11675 | 1461 { |
1462 /* XXX find out the jid */ | |
1463 gaim_blist_request_add_buddy(gaim_connection_get_account(gc), | |
1464 g_list_nth_data(row, 0), NULL, NULL); | |
1465 } | |
1466 | |
1467 static void user_search_result_cb(JabberStream *js, xmlnode *packet, gpointer data) | |
1468 { | |
1469 GaimNotifySearchResults *results; | |
1470 GaimNotifySearchColumn *column; | |
1471 xmlnode *x, *query, *item, *field; | |
1472 | |
1473 /* XXX error checking? */ | |
1474 if(!(query = xmlnode_get_child(packet, "query"))) | |
1475 return; | |
1476 | |
1477 results = gaim_notify_searchresults_new(); | |
1478 if((x = xmlnode_get_child_with_namespace(query, "x", "jabber:x:data"))) { | |
1479 xmlnode *reported; | |
1480 gaim_debug_info("jabber", "new-skool\n"); | |
1481 if((reported = xmlnode_get_child(x, "reported"))) { | |
1482 xmlnode *field = xmlnode_get_child(reported, "field"); | |
1483 while(field) { | |
1484 /* XXX keep track of this order, use it below */ | |
1485 const char *var = xmlnode_get_attrib(field, "var"); | |
1486 const char *label = xmlnode_get_attrib(field, "label"); | |
1487 if(var) { | |
1488 column = gaim_notify_searchresults_column_new(label ? label : var); | |
1489 gaim_notify_searchresults_column_add(results, column); | |
1490 } | |
1491 field = xmlnode_get_next_twin(field); | |
1492 } | |
1493 } | |
1494 item = xmlnode_get_child(x, "item"); | |
1495 while(item) { | |
1496 GList *row = NULL; | |
1497 field = xmlnode_get_child(item, "field"); | |
1498 while(field) { | |
13344 | 1499 xmlnode *valuenode = xmlnode_get_child(field, "value"); |
11675 | 1500 if(valuenode) { |
1501 char *value = xmlnode_get_data(valuenode); | |
1502 row = g_list_append(row, value); | |
1503 } | |
1504 field = xmlnode_get_next_twin(field); | |
1505 } | |
1506 gaim_notify_searchresults_row_add(results, row); | |
1507 | |
1508 item = xmlnode_get_next_twin(item); | |
1509 } | |
1510 } else { | |
1511 /* old skool */ | |
1512 gaim_debug_info("jabber", "old-skool\n"); | |
1513 | |
13571
02a8424191ea
[gaim-migrate @ 15950]
Richard Laager <rlaager@wiktel.com>
parents:
13545
diff
changeset
|
1514 column = gaim_notify_searchresults_column_new(_("JID")); |
11675 | 1515 gaim_notify_searchresults_column_add(results, column); |
13571
02a8424191ea
[gaim-migrate @ 15950]
Richard Laager <rlaager@wiktel.com>
parents:
13545
diff
changeset
|
1516 column = gaim_notify_searchresults_column_new(_("First Name")); |
11675 | 1517 gaim_notify_searchresults_column_add(results, column); |
13571
02a8424191ea
[gaim-migrate @ 15950]
Richard Laager <rlaager@wiktel.com>
parents:
13545
diff
changeset
|
1518 column = gaim_notify_searchresults_column_new(_("Last Name")); |
11675 | 1519 gaim_notify_searchresults_column_add(results, column); |
13571
02a8424191ea
[gaim-migrate @ 15950]
Richard Laager <rlaager@wiktel.com>
parents:
13545
diff
changeset
|
1520 column = gaim_notify_searchresults_column_new(_("Nickname")); |
11675 | 1521 gaim_notify_searchresults_column_add(results, column); |
13571
02a8424191ea
[gaim-migrate @ 15950]
Richard Laager <rlaager@wiktel.com>
parents:
13545
diff
changeset
|
1522 column = gaim_notify_searchresults_column_new(_("E-Mail")); |
11675 | 1523 gaim_notify_searchresults_column_add(results, column); |
1524 | |
1525 for(item = xmlnode_get_child(query, "item"); item; item = xmlnode_get_next_twin(item)) { | |
1526 const char *jid; | |
1527 xmlnode *node; | |
1528 GList *row = NULL; | |
1529 | |
1530 if(!(jid = xmlnode_get_attrib(item, "jid"))) | |
1531 continue; | |
1532 | |
1533 row = g_list_append(row, g_strdup(jid)); | |
1534 node = xmlnode_get_child(item, "first"); | |
1535 row = g_list_append(row, node ? xmlnode_get_data(node) : NULL); | |
1536 node = xmlnode_get_child(item, "last"); | |
1537 row = g_list_append(row, node ? xmlnode_get_data(node) : NULL); | |
1538 node = xmlnode_get_child(item, "nick"); | |
1539 row = g_list_append(row, node ? xmlnode_get_data(node) : NULL); | |
1540 node = xmlnode_get_child(item, "email"); | |
1541 row = g_list_append(row, node ? xmlnode_get_data(node) : NULL); | |
1542 gaim_debug_info("jabber", "row=%d\n", row); | |
1543 gaim_notify_searchresults_row_add(results, row); | |
1544 } | |
1545 } | |
1546 | |
12624
851b0bd7eb52
[gaim-migrate @ 14960]
Christopher O'Brien <siege@pidgin.im>
parents:
12467
diff
changeset
|
1547 gaim_notify_searchresults_button_add(results, GAIM_NOTIFY_BUTTON_ADD, |
11675 | 1548 user_search_result_add_buddy_cb); |
1549 | |
1550 gaim_notify_searchresults(js->gc, NULL, NULL, _("The following are the results of your search"), results, NULL, NULL); | |
1551 } | |
1552 | |
1553 static void user_search_x_data_cb(JabberStream *js, xmlnode *result, gpointer data) | |
1554 { | |
1555 xmlnode *query; | |
1556 JabberIq *iq; | |
13344 | 1557 char *dir_server = data; |
11675 | 1558 |
1559 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:search"); | |
1560 query = xmlnode_get_child(iq->node, "query"); | |
1561 | |
1562 xmlnode_insert_child(query, result); | |
1563 | |
1564 jabber_iq_set_callback(iq, user_search_result_cb, NULL); | |
13344 | 1565 xmlnode_set_attrib(iq->node, "to", dir_server); |
11675 | 1566 jabber_iq_send(iq); |
13344 | 1567 g_free(dir_server); |
11675 | 1568 } |
1569 | |
1570 struct user_search_info { | |
1571 JabberStream *js; | |
1572 char *directory_server; | |
1573 }; | |
1574 | |
1575 static void user_search_cancel_cb(struct user_search_info *usi, GaimRequestFields *fields) | |
1576 { | |
1577 g_free(usi->directory_server); | |
1578 g_free(usi); | |
1579 } | |
1580 | |
1581 static void user_search_cb(struct user_search_info *usi, GaimRequestFields *fields) | |
1582 { | |
1583 JabberStream *js = usi->js; | |
1584 JabberIq *iq; | |
1585 xmlnode *query; | |
1586 GList *groups, *flds; | |
1587 | |
1588 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:search"); | |
1589 query = xmlnode_get_child(iq->node, "query"); | |
1590 | |
1591 for(groups = gaim_request_fields_get_groups(fields); groups; groups = groups->next) { | |
1592 for(flds = gaim_request_field_group_get_fields(groups->data); | |
1593 flds; flds = flds->next) { | |
1594 GaimRequestField *field = flds->data; | |
1595 const char *id = gaim_request_field_get_id(field); | |
1596 const char *value = gaim_request_field_string_get_value(field); | |
1597 | |
1598 if(value && (!strcmp(id, "first") || !strcmp(id, "last") || !strcmp(id, "nick") || !strcmp(id, "email"))) { | |
1599 xmlnode *y = xmlnode_new_child(query, id); | |
1600 xmlnode_insert_data(y, value, -1); | |
1601 } | |
1602 } | |
1603 } | |
1604 | |
1605 jabber_iq_set_callback(iq, user_search_result_cb, NULL); | |
1606 xmlnode_set_attrib(iq->node, "to", usi->directory_server); | |
1607 jabber_iq_send(iq); | |
1608 | |
1609 g_free(usi->directory_server); | |
1610 g_free(usi); | |
1611 } | |
1612 | |
13616
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1613 #if 0 |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1614 /* This is for gettext only -- it will see this even though there's an #if 0. */ |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1615 |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1616 /* |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1617 * An incomplete list of server generated original language search |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1618 * comments for Jabber User Directories |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1619 * |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1620 * See discussion thread "Search comment for Jabber is not translatable" |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1621 * in gaim-i18n@lists.sourceforge.net (March 2006) |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1622 */ |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1623 static const char * jabber_user_dir_comments [] = { |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1624 /* current comment from Jabber User Directory users.jabber.org */ |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1625 N_("Find a contact by entering the search criteria in the given fields. " |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1626 "Note: Each field supports wild card searches (%)"), |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1627 NULL |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1628 }; |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1629 #endif |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1630 |
11675 | 1631 static void user_search_fields_result_cb(JabberStream *js, xmlnode *packet, gpointer data) |
1632 { | |
1633 xmlnode *query, *x; | |
13344 | 1634 const char *from, *type; |
11675 | 1635 |
12284
ecd471d1eeec
[gaim-migrate @ 14588]
Etan Reisner <pidgin@unreliablesource.net>
parents:
11675
diff
changeset
|
1636 if(!(from = xmlnode_get_attrib(packet, "from"))) |
11675 | 1637 return; |
1638 | |
13344 | 1639 if(!(type = xmlnode_get_attrib(packet, "type")) || !strcmp(type, "error")) { |
13633
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1640 char *msg = jabber_parse_error(js, packet); |
13792 | 1641 |
13633
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1642 if(!msg) |
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1643 msg = g_strdup(_("Unknown error")); |
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1644 |
13617
513d0e06f35f
[gaim-migrate @ 16003]
Richard Laager <rlaager@wiktel.com>
parents:
13616
diff
changeset
|
1645 gaim_notify_error(js->gc, _("Directory Query Failed"), |
13633
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1646 _("Could not query the directory server."), msg); |
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1647 g_free(msg); |
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1648 |
13344 | 1649 return; |
1650 } | |
1651 | |
11675 | 1652 |
1653 if(!(query = xmlnode_get_child(packet, "query"))) | |
1654 return; | |
1655 | |
13329 | 1656 if((x = xmlnode_get_child_with_namespace(query, "x", "jabber:x:data"))) { |
13344 | 1657 jabber_x_data_request(js, x, user_search_x_data_cb, g_strdup(from)); |
11675 | 1658 return; |
1659 } else { | |
1660 struct user_search_info *usi; | |
1661 xmlnode *instnode; | |
13616
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1662 char *instructions = NULL; |
11675 | 1663 GaimRequestFields *fields; |
1664 GaimRequestFieldGroup *group; | |
1665 GaimRequestField *field; | |
1666 | |
1667 /* old skool */ | |
1668 fields = gaim_request_fields_new(); | |
1669 group = gaim_request_field_group_new(NULL); | |
1670 gaim_request_fields_add_group(fields, group); | |
1671 | |
1672 if((instnode = xmlnode_get_child(query, "instructions"))) | |
13573
0b2e4a5a8e79
[gaim-migrate @ 15952]
Richard Laager <rlaager@wiktel.com>
parents:
13571
diff
changeset
|
1673 { |
0b2e4a5a8e79
[gaim-migrate @ 15952]
Richard Laager <rlaager@wiktel.com>
parents:
13571
diff
changeset
|
1674 char *tmp = xmlnode_get_data(instnode); |
13792 | 1675 |
13616
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1676 if(tmp) |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1677 { |
13792 | 1678 /* Try to translate the message (see static message |
13616
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1679 list in jabber_user_dir_comments[]) */ |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1680 instructions = g_strdup_printf(_("Server Instructions: %s"), _(tmp)); |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1681 g_free(tmp); |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1682 } |
13573
0b2e4a5a8e79
[gaim-migrate @ 15952]
Richard Laager <rlaager@wiktel.com>
parents:
13571
diff
changeset
|
1683 } |
13792 | 1684 |
13616
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1685 if(!instructions) |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1686 { |
11675 | 1687 instructions = g_strdup(_("Fill in one or more fields to search " |
13616
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1688 "for any matching Jabber users.")); |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1689 } |
11675 | 1690 |
1691 if(xmlnode_get_child(query, "first")) { | |
1692 field = gaim_request_field_string_new("first", _("First Name"), | |
1693 NULL, FALSE); | |
1694 gaim_request_field_group_add_field(group, field); | |
1695 } | |
1696 if(xmlnode_get_child(query, "last")) { | |
1697 field = gaim_request_field_string_new("last", _("Last Name"), | |
1698 NULL, FALSE); | |
1699 gaim_request_field_group_add_field(group, field); | |
1700 } | |
1701 if(xmlnode_get_child(query, "nick")) { | |
1702 field = gaim_request_field_string_new("nick", _("Nickname"), | |
1703 NULL, FALSE); | |
1704 gaim_request_field_group_add_field(group, field); | |
1705 } | |
1706 if(xmlnode_get_child(query, "email")) { | |
1707 field = gaim_request_field_string_new("email", _("E-Mail Address"), | |
1708 NULL, FALSE); | |
1709 gaim_request_field_group_add_field(group, field); | |
1710 } | |
1711 | |
1712 usi = g_new0(struct user_search_info, 1); | |
1713 usi->js = js; | |
1714 usi->directory_server = g_strdup(from); | |
1715 | |
1716 gaim_request_fields(js->gc, _("Search for Jabber users"), | |
1717 _("Search for Jabber users"), instructions, fields, | |
1718 _("Search"), G_CALLBACK(user_search_cb), | |
1719 _("Cancel"), G_CALLBACK(user_search_cancel_cb), usi); | |
1720 | |
1721 g_free(instructions); | |
1722 } | |
1723 } | |
1724 | |
1725 static void jabber_user_search_ok(JabberStream *js, const char *directory) | |
1726 { | |
1727 JabberIq *iq; | |
1728 | |
1729 /* XXX: should probably better validate the directory we're given */ | |
1730 if(!directory || !*directory) { | |
1731 gaim_notify_error(js->gc, _("Invalid Directory"), _("Invalid Directory"), NULL); | |
1732 return; | |
1733 } | |
1734 | |
1735 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:search"); | |
1736 xmlnode_set_attrib(iq->node, "to", directory); | |
1737 | |
1738 jabber_iq_set_callback(iq, user_search_fields_result_cb, NULL); | |
1739 | |
1740 jabber_iq_send(iq); | |
1741 } | |
1742 | |
1743 void jabber_user_search_begin(GaimPluginAction *action) | |
1744 { | |
1745 GaimConnection *gc = (GaimConnection *) action->context; | |
1746 JabberStream *js = gc->proto_data; | |
1747 | |
1748 gaim_request_input(gc, _("Enter a User Directory"), _("Enter a User Directory"), | |
1749 _("Select a user directory to search"), | |
1750 js->user_directories ? js->user_directories->data : "users.jabber.org", | |
1751 FALSE, FALSE, NULL, | |
1752 _("Search Directory"), GAIM_CALLBACK(jabber_user_search_ok), | |
1753 _("Cancel"), NULL, js); | |
1754 } | |
13792 | 1755 |
1756 | |
1757 |