Mercurial > pidgin
annotate src/protocols/jabber/buddy.c @ 14102:14e14f1ef1d8
[gaim-migrate @ 16732]
Jabber crashed when getting info from someone on your buddy list
if the JID consists only of the domain identifer. For example,
add "quser.alpha.qunu.com" to your buddy list then get their info.
This fixes the crashing. I'm not really sure if the fix is correct.
Can someone familiar with Jabber please look over this?
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Sun, 13 Aug 2006 05:50:19 +0000 |
parents | b9e9938b1afa |
children |
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; |
14068
6cb8bdc3366f
[gaim-migrate @ 16689]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14067
diff
changeset
|
536 char *cdata = NULL; |
7014 | 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); |
14068
6cb8bdc3366f
[gaim-migrate @ 16689]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14067
diff
changeset
|
567 } |
7014 | 568 |
569 if(strcmp(vc_tp->tag, "DESC") == 0) { | |
570 field = gaim_request_field_string_new(vc_tp->tag, | |
571 _(vc_tp->label), cdata, | |
572 TRUE); | |
573 } else { | |
574 field = gaim_request_field_string_new(vc_tp->tag, | |
575 _(vc_tp->label), cdata, | |
576 FALSE); | |
577 } | |
578 | |
14068
6cb8bdc3366f
[gaim-migrate @ 16689]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14067
diff
changeset
|
579 g_free(cdata); |
6cb8bdc3366f
[gaim-migrate @ 16689]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14067
diff
changeset
|
580 cdata = NULL; |
6cb8bdc3366f
[gaim-migrate @ 16689]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14067
diff
changeset
|
581 |
7014 | 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/>", | |
14093 | 677 _("Client"), jbr->client.name, |
13792 | 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 | |
14093 | 691 if (jbi->vcard_text != NULL) |
692 info_text = g_string_append(info_text, jbi->vcard_text); | |
13792 | 693 |
694 gaim_notify_userinfo(jbi->js->gc, jbi->jid, info_text->str, NULL, NULL); | |
695 | |
696 while(jbi->vcard_imgids) { | |
697 gaim_imgstore_unref(GPOINTER_TO_INT(jbi->vcard_imgids->data)); | |
698 jbi->vcard_imgids = g_slist_delete_link(jbi->vcard_imgids, jbi->vcard_imgids); | |
699 } | |
700 | |
701 g_string_free(info_text, TRUE); | |
702 | |
14093 | 703 if (jbi->timeout_handle > 0) |
704 gaim_timeout_remove(jbi->timeout_handle); | |
705 | |
13792 | 706 g_free(jbi->jid); |
707 g_hash_table_destroy(jbi->resources); | |
708 g_free(jbi->vcard_text); | |
709 g_free(jbi); | |
710 } | |
711 | |
712 static void jabber_buddy_info_remove_id(JabberBuddyInfo *jbi, const char *id) | |
713 { | |
714 GSList *l = jbi->ids; | |
715 | |
716 if(!id) | |
717 return; | |
718 | |
719 while(l) { | |
720 if(!strcmp(id, l->data)) { | |
721 jbi->ids = g_slist_remove(jbi->ids, l->data); | |
722 return; | |
723 } | |
724 l = l->next; | |
725 } | |
726 } | |
727 | |
728 static void jabber_vcard_parse(JabberStream *js, xmlnode *packet, gpointer data) | |
729 { | |
14067
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
730 const char *id, *from; |
13792 | 731 GString *info_text; |
732 char *bare_jid; | |
733 char *text; | |
734 xmlnode *vcard; | |
735 GaimBuddy *b; | |
736 JabberBuddyInfo *jbi = data; | |
737 | |
738 from = xmlnode_get_attrib(packet, "from"); | |
739 id = xmlnode_get_attrib(packet, "id"); | |
740 | |
741 if(!jbi) | |
742 return; | |
743 | |
14067
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
744 jabber_buddy_info_remove_id(jbi, id); |
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
745 |
13792 | 746 if(!from) |
747 return; | |
748 | |
14067
f3ed5f4efcae
[gaim-migrate @ 16688]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
13806
diff
changeset
|
749 if(!jabber_buddy_find(js, from, FALSE)) |
13792 | 750 return; |
751 | |
752 /* XXX: handle the error case */ | |
753 | |
754 bare_jid = jabber_get_bare_jid(from); | |
755 | |
756 b = gaim_find_buddy(js->gc->account, bare_jid); | |
757 | |
758 info_text = g_string_new(""); | |
759 | |
10189 | 760 if((vcard = xmlnode_get_child(packet, "vCard")) || |
761 (vcard = xmlnode_get_child_with_namespace(packet, "query", "vcard-temp"))) { | |
7014 | 762 xmlnode *child; |
763 for(child = vcard->child; child; child = child->next) | |
764 { | |
765 xmlnode *child2; | |
766 | |
8135 | 767 if(child->type != XMLNODE_TYPE_TAG) |
7014 | 768 continue; |
769 | |
770 text = xmlnode_get_data(child); | |
771 if(text && !strcmp(child->name, "FN")) { | |
8213 | 772 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 773 _("Full Name"), text); |
774 } else if(!strcmp(child->name, "N")) { | |
775 for(child2 = child->child; child2; child2 = child2->next) | |
776 { | |
777 char *text2; | |
778 | |
8135 | 779 if(child2->type != XMLNODE_TYPE_TAG) |
7014 | 780 continue; |
781 | |
782 text2 = xmlnode_get_data(child2); | |
783 if(text2 && !strcmp(child2->name, "FAMILY")) { | |
784 g_string_append_printf(info_text, | |
8213 | 785 "<b>%s:</b> %s<br/>", |
7014 | 786 _("Family Name"), text2); |
787 } else if(text2 && !strcmp(child2->name, "GIVEN")) { | |
788 g_string_append_printf(info_text, | |
8213 | 789 "<b>%s:</b> %s<br/>", |
7014 | 790 _("Given Name"), text2); |
791 } else if(text2 && !strcmp(child2->name, "MIDDLE")) { | |
792 g_string_append_printf(info_text, | |
8213 | 793 "<b>%s:</b> %s<br/>", |
7014 | 794 _("Middle Name"), text2); |
795 } | |
796 g_free(text2); | |
797 } | |
798 } else if(text && !strcmp(child->name, "NICKNAME")) { | |
799 serv_got_alias(js->gc, from, text); | |
7955 | 800 if(b) { |
801 gaim_blist_node_set_string((GaimBlistNode*)b, "servernick", text); | |
802 } | |
8213 | 803 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 804 _("Nickname"), text); |
805 } else if(text && !strcmp(child->name, "BDAY")) { | |
8213 | 806 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 807 _("Birthday"), text); |
808 } else if(!strcmp(child->name, "ADR")) { | |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
809 gboolean address_line_added = FALSE; |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
810 |
7014 | 811 for(child2 = child->child; child2; child2 = child2->next) |
812 { | |
813 char *text2; | |
814 | |
8135 | 815 if(child2->type != XMLNODE_TYPE_TAG) |
7014 | 816 continue; |
817 | |
818 text2 = xmlnode_get_data(child2); | |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
819 if (text2 == NULL) |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
820 continue; |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
821 |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
822 /* 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
|
823 * elements are empty. */ |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
824 if (!address_line_added) |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
825 { |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
826 g_string_append_printf(info_text, "<b>%s:</b><br/>", |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
827 _("Address")); |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
828 address_line_added = TRUE; |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
829 } |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
830 |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
831 if(!strcmp(child2->name, "POBOX")) { |
7014 | 832 g_string_append_printf(info_text, |
8213 | 833 " <b>%s:</b> %s<br/>", |
7014 | 834 _("P.O. Box"), text2); |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
835 } else if(!strcmp(child2->name, "EXTADR")) { |
7014 | 836 g_string_append_printf(info_text, |
8213 | 837 " <b>%s:</b> %s<br/>", |
7014 | 838 _("Extended Address"), text2); |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
839 } else if(!strcmp(child2->name, "STREET")) { |
7014 | 840 g_string_append_printf(info_text, |
8213 | 841 " <b>%s:</b> %s<br/>", |
7014 | 842 _("Street Address"), text2); |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
843 } else if(!strcmp(child2->name, "LOCALITY")) { |
7014 | 844 g_string_append_printf(info_text, |
8213 | 845 " <b>%s:</b> %s<br/>", |
7014 | 846 _("Locality"), text2); |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
847 } else if(!strcmp(child2->name, "REGION")) { |
7014 | 848 g_string_append_printf(info_text, |
8213 | 849 " <b>%s:</b> %s<br/>", |
7014 | 850 _("Region"), text2); |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
851 } else if(!strcmp(child2->name, "PCODE")) { |
7014 | 852 g_string_append_printf(info_text, |
8213 | 853 " <b>%s:</b> %s<br/>", |
7014 | 854 _("Postal Code"), text2); |
12933
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
855 } else if(!strcmp(child2->name, "CTRY") |
75ac13ab161f
[gaim-migrate @ 15286]
Richard Laager <rlaager@wiktel.com>
parents:
12919
diff
changeset
|
856 || !strcmp(child2->name, "COUNTRY")) { |
7014 | 857 g_string_append_printf(info_text, |
8213 | 858 " <b>%s:</b> %s<br/>", |
7014 | 859 _("Country"), text2); |
860 } | |
861 g_free(text2); | |
862 } | |
863 } else if(!strcmp(child->name, "TEL")) { | |
864 char *number; | |
865 if((child2 = xmlnode_get_child(child, "NUMBER"))) { | |
866 /* show what kind of number it is */ | |
867 number = xmlnode_get_data(child2); | |
868 if(number) { | |
869 g_string_append_printf(info_text, | |
8213 | 870 "<b>%s:</b> %s<br/>", _("Telephone"), number); |
7014 | 871 g_free(number); |
872 } | |
873 } else if((number = xmlnode_get_data(child))) { | |
874 /* lots of clients (including gaim) do this, but it's | |
875 * out of spec */ | |
876 g_string_append_printf(info_text, | |
8213 | 877 "<b>%s:</b> %s<br/>", _("Telephone"), number); |
7014 | 878 g_free(number); |
879 } | |
880 } else if(!strcmp(child->name, "EMAIL")) { | |
881 char *userid; | |
882 if((child2 = xmlnode_get_child(child, "USERID"))) { | |
883 /* show what kind of email it is */ | |
884 userid = xmlnode_get_data(child2); | |
885 if(userid) { | |
886 g_string_append_printf(info_text, | |
8213 | 887 "<b>%s:</b> <a href='mailto:%s'>%s</a><br/>", |
13545
cfc2f7fcb3dd
[gaim-migrate @ 15922]
Richard Laager <rlaager@wiktel.com>
parents:
13344
diff
changeset
|
888 _("E-Mail"), userid, userid); |
7014 | 889 g_free(userid); |
890 } | |
891 } else if((userid = xmlnode_get_data(child))) { | |
892 /* lots of clients (including gaim) do this, but it's | |
893 * out of spec */ | |
894 g_string_append_printf(info_text, | |
8213 | 895 "<b>%s:</b> <a href='mailto:%s'>%s</a><br/>", |
13545
cfc2f7fcb3dd
[gaim-migrate @ 15922]
Richard Laager <rlaager@wiktel.com>
parents:
13344
diff
changeset
|
896 _("E-Mail"), userid, userid); |
7014 | 897 g_free(userid); |
898 } | |
899 } else if(!strcmp(child->name, "ORG")) { | |
900 for(child2 = child->child; child2; child2 = child2->next) | |
901 { | |
902 char *text2; | |
903 | |
8135 | 904 if(child2->type != XMLNODE_TYPE_TAG) |
7014 | 905 continue; |
906 | |
907 text2 = xmlnode_get_data(child2); | |
908 if(text2 && !strcmp(child2->name, "ORGNAME")) { | |
909 g_string_append_printf(info_text, | |
8213 | 910 "<b>%s:</b> %s<br/>", |
7014 | 911 _("Organization Name"), text2); |
912 } else if(text2 && !strcmp(child2->name, "ORGUNIT")) { | |
913 g_string_append_printf(info_text, | |
8213 | 914 "<b>%s:</b> %s<br/>", |
7014 | 915 _("Organization Unit"), text2); |
916 } | |
917 g_free(text2); | |
918 } | |
919 } else if(text && !strcmp(child->name, "TITLE")) { | |
8213 | 920 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 921 _("Title"), text); |
922 } else if(text && !strcmp(child->name, "ROLE")) { | |
8213 | 923 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
7014 | 924 _("Role"), text); |
925 } else if(text && !strcmp(child->name, "DESC")) { | |
8213 | 926 g_string_append_printf(info_text, "<b>%s:</b> %s<br/>", |
927 _("Description"), text); | |
7076 | 928 } else if(!strcmp(child->name, "PHOTO") || |
929 !strcmp(child->name, "LOGO")) { | |
10941 | 930 char *bintext = NULL; |
931 xmlnode *binval; | |
11361 | 932 |
933 if( ((binval = xmlnode_get_child(child, "BINVAL")) && | |
934 (bintext = xmlnode_get_data(binval))) || | |
935 (bintext = xmlnode_get_data(child))) { | |
11127 | 936 gsize size; |
11137 | 937 guchar *data; |
11127 | 938 int i; |
10941 | 939 unsigned char hashval[20]; |
11127 | 940 char *p, hash[41]; |
10941 | 941 gboolean photo = (strcmp(child->name, "PHOTO") == 0); |
10189 | 942 |
11361 | 943 data = gaim_base64_decode(bintext, &size); |
7076 | 944 |
13792 | 945 jbi->vcard_imgids = g_slist_prepend(jbi->vcard_imgids, GINT_TO_POINTER(gaim_imgstore_add(data, size, "logo.png"))); |
10941 | 946 g_string_append_printf(info_text, |
947 "<b>%s:</b> <img id='%d'><br/>", | |
948 photo ? _("Photo") : _("Logo"), | |
13792 | 949 GPOINTER_TO_INT(jbi->vcard_imgids->data)); |
7076 | 950 |
10941 | 951 gaim_buddy_icons_set_for_user(js->gc->account, bare_jid, |
952 data, size); | |
10189 | 953 |
11183 | 954 gaim_cipher_digest_region("sha1", (guchar *)data, size, |
10941 | 955 sizeof(hashval), hashval, NULL); |
956 p = hash; | |
957 for(i=0; i<20; i++, p+=2) | |
958 snprintf(p, 3, "%02x", hashval[i]); | |
959 gaim_blist_node_set_string((GaimBlistNode*)b, "avatar_hash", hash); | |
10189 | 960 |
10941 | 961 g_free(data); |
962 g_free(bintext); | |
963 } | |
7014 | 964 } |
965 g_free(text); | |
966 } | |
967 } | |
968 | |
13792 | 969 jbi->vcard_text = gaim_strdup_withhtml(info_text->str); |
970 g_string_free(info_text, TRUE); | |
971 g_free(bare_jid); | |
972 | |
973 jabber_buddy_info_show_if_ready(jbi); | |
974 } | |
975 | |
8213 | 976 |
13792 | 977 static void jabber_buddy_info_resource_free(gpointer data) |
978 { | |
979 JabberBuddyInfoResource *jbri = data; | |
980 g_free(jbri); | |
981 } | |
982 | |
983 static void jabber_version_parse(JabberStream *js, xmlnode *packet, gpointer data) | |
984 { | |
985 JabberBuddyInfo *jbi = data; | |
986 const char *type, *id, *from; | |
987 xmlnode *query; | |
988 char *resource_name; | |
989 | |
990 g_return_if_fail(jbi != NULL); | |
991 | |
992 type = xmlnode_get_attrib(packet, "type"); | |
993 id = xmlnode_get_attrib(packet, "id"); | |
994 from = xmlnode_get_attrib(packet, "from"); | |
7014 | 995 |
13792 | 996 jabber_buddy_info_remove_id(jbi, id); |
997 | |
998 if(!from) | |
999 return; | |
1000 | |
1001 resource_name = jabber_get_resource(from); | |
1002 | |
1003 if(resource_name) { | |
1004 if(type && !strcmp(type, "result")) { | |
1005 if((query = xmlnode_get_child(packet, "query"))) { | |
1006 JabberBuddyResource *jbr = jabber_buddy_find_resource(jbi->jb, resource_name); | |
1007 if(jbr) { | |
1008 xmlnode *node; | |
1009 if((node = xmlnode_get_child(query, "name"))) { | |
1010 jbr->client.name = xmlnode_get_data(node); | |
1011 } | |
1012 if((node = xmlnode_get_child(query, "version"))) { | |
1013 jbr->client.version = xmlnode_get_data(node); | |
1014 } | |
1015 if((node = xmlnode_get_child(query, "os"))) { | |
1016 jbr->client.os = xmlnode_get_data(node); | |
1017 } | |
1018 } | |
1019 } | |
1020 } | |
1021 g_free(resource_name); | |
10189 | 1022 } |
13792 | 1023 |
1024 jabber_buddy_info_show_if_ready(jbi); | |
7014 | 1025 } |
1026 | |
13792 | 1027 static void jabber_last_parse(JabberStream *js, xmlnode *packet, gpointer data) |
1028 { | |
1029 JabberBuddyInfo *jbi = data; | |
1030 xmlnode *query; | |
1031 char *resource_name; | |
1032 const char *type, *id, *from, *seconds; | |
1033 | |
1034 g_return_if_fail(jbi != NULL); | |
1035 | |
1036 type = xmlnode_get_attrib(packet, "type"); | |
1037 id = xmlnode_get_attrib(packet, "id"); | |
1038 from = xmlnode_get_attrib(packet, "from"); | |
1039 | |
1040 jabber_buddy_info_remove_id(jbi, id); | |
1041 | |
1042 if(!from) | |
1043 return; | |
1044 | |
1045 resource_name = jabber_get_resource(from); | |
1046 | |
1047 if(resource_name) { | |
1048 if(type && !strcmp(type, "result")) { | |
1049 if((query = xmlnode_get_child(packet, "query"))) { | |
1050 seconds = xmlnode_get_attrib(query, "seconds"); | |
1051 if(seconds) { | |
1052 char *end = NULL; | |
1053 long sec = strtol(seconds, &end, 10); | |
1054 if(end != seconds) { | |
1055 JabberBuddyInfoResource *jbir = g_hash_table_lookup(jbi->resources, resource_name); | |
1056 if(jbir) { | |
1057 jbir->idle_seconds = sec; | |
1058 } | |
1059 } | |
1060 } | |
1061 } | |
1062 } | |
1063 g_free(resource_name); | |
1064 } | |
1065 | |
1066 jabber_buddy_info_show_if_ready(jbi); | |
1067 } | |
1068 | |
1069 static gboolean jabber_buddy_get_info_timeout(gpointer data) | |
1070 { | |
1071 JabberBuddyInfo *jbi = data; | |
1072 | |
1073 /* remove the pending callbacks */ | |
1074 while(jbi->ids) { | |
1075 char *id = jbi->ids->data; | |
1076 jabber_iq_remove_callback_by_id(jbi->js, id); | |
1077 g_free(id); | |
1078 jbi->ids = g_slist_remove(jbi->ids, id); | |
1079 } | |
1080 | |
1081 jbi->timeout_handle = 0; | |
1082 | |
1083 jabber_buddy_info_show_if_ready(jbi); | |
1084 | |
1085 return FALSE; | |
1086 } | |
1087 | |
1088 static void jabber_buddy_get_info_for_jid(JabberStream *js, const char *jid) | |
7014 | 1089 { |
1090 JabberIq *iq; | |
1091 xmlnode *vcard; | |
13792 | 1092 GList *resources; |
1093 JabberBuddy *jb; | |
1094 JabberBuddyInfo *jbi; | |
1095 | |
1096 jb = jabber_buddy_find(js, jid, TRUE); | |
1097 | |
1098 /* invalid JID */ | |
1099 if(!jb) | |
1100 return; | |
1101 | |
1102 jbi = g_new0(JabberBuddyInfo, 1); | |
1103 jbi->jid = g_strdup(jid); | |
1104 jbi->js = js; | |
1105 jbi->jb = jb; | |
1106 jbi->resources = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, jabber_buddy_info_resource_free); | |
7014 | 1107 |
1108 iq = jabber_iq_new(js, JABBER_IQ_GET); | |
1109 | |
13792 | 1110 xmlnode_set_attrib(iq->node, "to", jid); |
7014 | 1111 vcard = xmlnode_new_child(iq->node, "vCard"); |
13806 | 1112 xmlnode_set_namespace(vcard, "vcard-temp"); |
7014 | 1113 |
13792 | 1114 jabber_iq_set_callback(iq, jabber_vcard_parse, jbi); |
1115 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id)); | |
7014 | 1116 |
1117 jabber_iq_send(iq); | |
13792 | 1118 |
1119 for(resources = jb->resources; resources; resources = resources->next) | |
1120 { | |
1121 JabberBuddyResource *jbr = resources->data; | |
14102 | 1122 JabberBuddyInfoResource *jbir; |
13792 | 1123 char *full_jid; |
14102 | 1124 |
1125 if ((strchr(jid, '/') == NULL) && (jbr->name != NULL)) { | |
1126 full_jid = g_strdup_printf("%s/%s", jid, jbr->name); | |
1127 } else { | |
13792 | 1128 full_jid = g_strdup(jid); |
1129 } | |
1130 | |
14102 | 1131 if (jbr->name != NULL) |
1132 { | |
1133 jbir = g_new0(JabberBuddyInfoResource, 1); | |
1134 g_hash_table_insert(jbi->resources, g_strdup(jbr->name), jbir); | |
1135 } | |
13792 | 1136 |
1137 if(!jbr->client.name) { | |
1138 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:version"); | |
1139 xmlnode_set_attrib(iq->node, "to", full_jid); | |
1140 jabber_iq_set_callback(iq, jabber_version_parse, jbi); | |
1141 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id)); | |
1142 jabber_iq_send(iq); | |
1143 } | |
1144 | |
1145 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:last"); | |
1146 xmlnode_set_attrib(iq->node, "to", full_jid); | |
1147 jabber_iq_set_callback(iq, jabber_last_parse, jbi); | |
1148 jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id)); | |
1149 jabber_iq_send(iq); | |
1150 | |
1151 g_free(full_jid); | |
1152 } | |
1153 | |
1154 jbi->timeout_handle = gaim_timeout_add(30000, jabber_buddy_get_info_timeout, jbi); | |
7014 | 1155 } |
1156 | |
10189 | 1157 void jabber_buddy_get_info(GaimConnection *gc, const char *who) |
1158 { | |
1159 JabberStream *js = gc->proto_data; | |
1160 char *bare_jid = jabber_get_bare_jid(who); | |
1161 | |
1162 if(bare_jid) { | |
1163 jabber_buddy_get_info_for_jid(js, bare_jid); | |
1164 g_free(bare_jid); | |
1165 } | |
1166 } | |
1167 | |
7014 | 1168 void jabber_buddy_get_info_chat(GaimConnection *gc, int id, |
1169 const char *resource) | |
1170 { | |
1171 JabberStream *js = gc->proto_data; | |
1172 JabberChat *chat = jabber_chat_find_by_id(js, id); | |
1173 char *full_jid; | |
1174 | |
1175 if(!chat) | |
1176 return; | |
1177 | |
1178 full_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, resource); | |
10189 | 1179 jabber_buddy_get_info_for_jid(js, full_jid); |
7014 | 1180 g_free(full_jid); |
1181 } | |
1182 | |
7395 | 1183 |
7014 | 1184 static void jabber_buddy_set_invisibility(JabberStream *js, const char *who, |
1185 gboolean invisible) | |
1186 { | |
9944 | 1187 GaimPresence *gpresence; |
1188 GaimAccount *account; | |
1189 GaimStatus *status; | |
7014 | 1190 JabberBuddy *jb = jabber_buddy_find(js, who, TRUE); |
1191 xmlnode *presence; | |
9954 | 1192 JabberBuddyState state; |
1193 const char *msg; | |
1194 int priority; | |
7014 | 1195 |
9944 | 1196 account = gaim_connection_get_account(js->gc); |
1197 gpresence = gaim_account_get_presence(account); | |
1198 status = gaim_presence_get_active_status(gpresence); | |
1199 | |
9954 | 1200 gaim_status_to_jabber(status, &state, &msg, &priority); |
1201 presence = jabber_presence_create(state, msg, priority); | |
1202 | |
7014 | 1203 xmlnode_set_attrib(presence, "to", who); |
1204 if(invisible) { | |
1205 xmlnode_set_attrib(presence, "type", "invisible"); | |
1206 jb->invisible |= JABBER_INVIS_BUDDY; | |
1207 } else { | |
1208 jb->invisible &= ~JABBER_INVIS_BUDDY; | |
1209 } | |
1210 | |
1211 jabber_send(js, presence); | |
1212 xmlnode_free(presence); | |
1213 } | |
1214 | |
9030 | 1215 static void jabber_buddy_make_invisible(GaimBlistNode *node, gpointer data) |
7014 | 1216 { |
9030 | 1217 GaimBuddy *buddy; |
1218 GaimConnection *gc; | |
1219 JabberStream *js; | |
1220 | |
1221 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
1222 | |
1223 buddy = (GaimBuddy *) node; | |
1224 gc = gaim_account_get_connection(buddy->account); | |
1225 js = gc->proto_data; | |
1226 | |
1227 jabber_buddy_set_invisibility(js, buddy->name, TRUE); | |
7014 | 1228 } |
1229 | |
9030 | 1230 static void jabber_buddy_make_visible(GaimBlistNode *node, gpointer data) |
7014 | 1231 { |
9030 | 1232 GaimBuddy *buddy; |
1233 GaimConnection *gc; | |
1234 JabberStream *js; | |
7014 | 1235 |
9030 | 1236 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); |
7014 | 1237 |
9030 | 1238 buddy = (GaimBuddy *) node; |
1239 gc = gaim_account_get_connection(buddy->account); | |
1240 js = gc->proto_data; | |
1241 | |
1242 jabber_buddy_set_invisibility(js, buddy->name, FALSE); | |
7014 | 1243 } |
1244 | |
9030 | 1245 static void jabber_buddy_cancel_presence_notification(GaimBlistNode *node, |
1246 gpointer data) | |
7014 | 1247 { |
9030 | 1248 GaimBuddy *buddy; |
1249 GaimConnection *gc; | |
1250 JabberStream *js; | |
1251 | |
1252 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
7014 | 1253 |
9030 | 1254 buddy = (GaimBuddy *) node; |
1255 gc = gaim_account_get_connection(buddy->account); | |
1256 js = gc->proto_data; | |
1257 | |
1258 /* I wonder if we should prompt the user before doing this */ | |
1259 jabber_presence_subscription_set(js, buddy->name, "unsubscribed"); | |
7014 | 1260 } |
1261 | |
9030 | 1262 static void jabber_buddy_rerequest_auth(GaimBlistNode *node, gpointer data) |
7250 | 1263 { |
9030 | 1264 GaimBuddy *buddy; |
1265 GaimConnection *gc; | |
1266 JabberStream *js; | |
1267 | |
1268 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
7250 | 1269 |
9030 | 1270 buddy = (GaimBuddy *) node; |
1271 gc = gaim_account_get_connection(buddy->account); | |
1272 js = gc->proto_data; | |
1273 | |
1274 jabber_presence_subscription_set(js, buddy->name, "subscribe"); | |
7250 | 1275 } |
1276 | |
9030 | 1277 |
1278 static void jabber_buddy_unsubscribe(GaimBlistNode *node, gpointer data) | |
7014 | 1279 { |
9030 | 1280 GaimBuddy *buddy; |
1281 GaimConnection *gc; | |
1282 JabberStream *js; | |
1283 | |
1284 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
1285 | |
1286 buddy = (GaimBuddy *) node; | |
1287 gc = gaim_account_get_connection(buddy->account); | |
1288 js = gc->proto_data; | |
1289 | |
1290 jabber_presence_subscription_set(js, buddy->name, "unsubscribe"); | |
1291 } | |
1292 | |
1293 | |
12323
fc464a0abccc
[gaim-migrate @ 14627]
Richard Laager <rlaager@wiktel.com>
parents:
12284
diff
changeset
|
1294 static GList *jabber_buddy_menu(GaimBuddy *buddy) |
9030 | 1295 { |
1296 GaimConnection *gc = gaim_account_get_connection(buddy->account); | |
1297 JabberStream *js = gc->proto_data; | |
1298 JabberBuddy *jb = jabber_buddy_find(js, buddy->name, TRUE); | |
1299 | |
7014 | 1300 GList *m = NULL; |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1301 GaimMenuAction *act; |
7395 | 1302 |
1303 if(!jb) | |
1304 return m; | |
1305 | |
8185 | 1306 /* XXX: fix the NOT ME below */ |
1307 | |
1308 if(js->protocol_version == JABBER_PROTO_0_9 /* && NOT ME */) { | |
8166 | 1309 if(jb->invisible & JABBER_INVIS_BUDDY) { |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1310 act = gaim_menu_action_new(_("Un-hide From"), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1311 GAIM_CALLBACK(jabber_buddy_make_visible), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1312 NULL, NULL); |
8166 | 1313 } else { |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1314 act = gaim_menu_action_new(_("Temporarily Hide From"), |
13019
8504ce176d38
[gaim-migrate @ 15372]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12933
diff
changeset
|
1315 GAIM_CALLBACK(jabber_buddy_make_invisible), |
8504ce176d38
[gaim-migrate @ 15372]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12933
diff
changeset
|
1316 NULL, NULL); |
8166 | 1317 } |
9030 | 1318 m = g_list_append(m, act); |
7014 | 1319 } |
1320 | |
8185 | 1321 if(jb->subscription & JABBER_SUB_FROM /* && NOT ME */) { |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1322 act = gaim_menu_action_new(_("Cancel Presence Notification"), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1323 GAIM_CALLBACK(jabber_buddy_cancel_presence_notification), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1324 NULL, NULL); |
9030 | 1325 m = g_list_append(m, act); |
7014 | 1326 } |
1327 | |
1328 if(!(jb->subscription & JABBER_SUB_TO)) { | |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1329 act = gaim_menu_action_new(_("(Re-)Request authorization"), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1330 GAIM_CALLBACK(jabber_buddy_rerequest_auth), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1331 NULL, NULL); |
9030 | 1332 m = g_list_append(m, act); |
1333 | |
8185 | 1334 } else /* if(NOT ME) */{ |
9030 | 1335 |
1336 /* shouldn't this just happen automatically when the buddy is | |
1337 removed? */ | |
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1338 act = gaim_menu_action_new(_("Unsubscribe"), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1339 GAIM_CALLBACK(jabber_buddy_unsubscribe), |
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12683
diff
changeset
|
1340 NULL, NULL); |
9030 | 1341 m = g_list_append(m, act); |
7014 | 1342 } |
1343 | |
1344 return m; | |
1345 } | |
9030 | 1346 |
1347 GList * | |
1348 jabber_blist_node_menu(GaimBlistNode *node) | |
1349 { | |
1350 if(GAIM_BLIST_NODE_IS_BUDDY(node)) { | |
1351 return jabber_buddy_menu((GaimBuddy *) node); | |
1352 } else { | |
1353 return NULL; | |
1354 } | |
1355 } | |
1356 | |
1357 | |
9954 | 1358 const char * |
1359 jabber_buddy_state_get_name(JabberBuddyState state) | |
1360 { | |
1361 switch(state) { | |
1362 case JABBER_BUDDY_STATE_UNKNOWN: | |
1363 return _("Unknown"); | |
1364 case JABBER_BUDDY_STATE_ERROR: | |
1365 return _("Error"); | |
1366 case JABBER_BUDDY_STATE_UNAVAILABLE: | |
1367 return _("Offline"); | |
1368 case JABBER_BUDDY_STATE_ONLINE: | |
12467
1b57012eec7b
[gaim-migrate @ 14777]
Richard Laager <rlaager@wiktel.com>
parents:
12323
diff
changeset
|
1369 return _("Available"); |
9954 | 1370 case JABBER_BUDDY_STATE_CHAT: |
1371 return _("Chatty"); | |
1372 case JABBER_BUDDY_STATE_AWAY: | |
1373 return _("Away"); | |
1374 case JABBER_BUDDY_STATE_XA: | |
1375 return _("Extended Away"); | |
1376 case JABBER_BUDDY_STATE_DND: | |
1377 return _("Do Not Disturb"); | |
1378 } | |
1379 | |
1380 return _("Unknown"); | |
1381 } | |
1382 | |
1383 JabberBuddyState jabber_buddy_status_id_get_state(const char *id) { | |
1384 if(!id) | |
1385 return JABBER_BUDDY_STATE_UNKNOWN; | |
11540 | 1386 if(!strcmp(id, "available")) |
9954 | 1387 return JABBER_BUDDY_STATE_ONLINE; |
12683 | 1388 if(!strcmp(id, "freeforchat")) |
1389 return JABBER_BUDDY_STATE_CHAT; | |
1390 if(!strcmp(id, "away")) | |
1391 return JABBER_BUDDY_STATE_AWAY; | |
1392 if(!strcmp(id, "extended_away")) | |
1393 return JABBER_BUDDY_STATE_XA; | |
1394 if(!strcmp(id, "dnd")) | |
1395 return JABBER_BUDDY_STATE_DND; | |
1396 if(!strcmp(id, "offline")) | |
1397 return JABBER_BUDDY_STATE_UNAVAILABLE; | |
1398 if(!strcmp(id, "error")) | |
1399 return JABBER_BUDDY_STATE_ERROR; | |
1400 | |
1401 return JABBER_BUDDY_STATE_UNKNOWN; | |
1402 } | |
1403 | |
1404 JabberBuddyState jabber_buddy_show_get_state(const char *id) { | |
1405 if(!id) | |
1406 return JABBER_BUDDY_STATE_UNKNOWN; | |
1407 if(!strcmp(id, "available")) | |
1408 return JABBER_BUDDY_STATE_ONLINE; | |
9954 | 1409 if(!strcmp(id, "chat")) |
1410 return JABBER_BUDDY_STATE_CHAT; | |
1411 if(!strcmp(id, "away")) | |
1412 return JABBER_BUDDY_STATE_AWAY; | |
1413 if(!strcmp(id, "xa")) | |
1414 return JABBER_BUDDY_STATE_XA; | |
1415 if(!strcmp(id, "dnd")) | |
1416 return JABBER_BUDDY_STATE_DND; | |
1417 if(!strcmp(id, "offline")) | |
1418 return JABBER_BUDDY_STATE_UNAVAILABLE; | |
1419 if(!strcmp(id, "error")) | |
1420 return JABBER_BUDDY_STATE_ERROR; | |
1421 | |
1422 return JABBER_BUDDY_STATE_UNKNOWN; | |
1423 } | |
1424 | |
12683 | 1425 const char *jabber_buddy_state_get_show(JabberBuddyState state) { |
9954 | 1426 switch(state) { |
1427 case JABBER_BUDDY_STATE_CHAT: | |
1428 return "chat"; | |
1429 case JABBER_BUDDY_STATE_AWAY: | |
1430 return "away"; | |
1431 case JABBER_BUDDY_STATE_XA: | |
1432 return "xa"; | |
1433 case JABBER_BUDDY_STATE_DND: | |
1434 return "dnd"; | |
1435 case JABBER_BUDDY_STATE_ONLINE: | |
11540 | 1436 return "available"; |
9954 | 1437 case JABBER_BUDDY_STATE_UNKNOWN: |
1438 case JABBER_BUDDY_STATE_ERROR: | |
1439 return NULL; | |
1440 case JABBER_BUDDY_STATE_UNAVAILABLE: | |
1441 return "offline"; | |
1442 } | |
1443 return NULL; | |
1444 } | |
11675 | 1445 |
12683 | 1446 const char *jabber_buddy_state_get_status_id(JabberBuddyState state) { |
1447 switch(state) { | |
1448 case JABBER_BUDDY_STATE_CHAT: | |
1449 return "freeforchat"; | |
1450 case JABBER_BUDDY_STATE_AWAY: | |
1451 return "away"; | |
1452 case JABBER_BUDDY_STATE_XA: | |
1453 return "extended_away"; | |
1454 case JABBER_BUDDY_STATE_DND: | |
1455 return "dnd"; | |
1456 case JABBER_BUDDY_STATE_ONLINE: | |
1457 return "available"; | |
1458 case JABBER_BUDDY_STATE_UNKNOWN: | |
13756 | 1459 return "available"; |
12683 | 1460 case JABBER_BUDDY_STATE_ERROR: |
13756 | 1461 return "error"; |
12683 | 1462 case JABBER_BUDDY_STATE_UNAVAILABLE: |
1463 return "offline"; | |
1464 } | |
1465 return NULL; | |
1466 } | |
1467 | |
13640 | 1468 static void user_search_result_add_buddy_cb(GaimConnection *gc, GList *row, void *user_data) |
11675 | 1469 { |
1470 /* XXX find out the jid */ | |
1471 gaim_blist_request_add_buddy(gaim_connection_get_account(gc), | |
1472 g_list_nth_data(row, 0), NULL, NULL); | |
1473 } | |
1474 | |
1475 static void user_search_result_cb(JabberStream *js, xmlnode *packet, gpointer data) | |
1476 { | |
1477 GaimNotifySearchResults *results; | |
1478 GaimNotifySearchColumn *column; | |
1479 xmlnode *x, *query, *item, *field; | |
1480 | |
1481 /* XXX error checking? */ | |
1482 if(!(query = xmlnode_get_child(packet, "query"))) | |
1483 return; | |
1484 | |
1485 results = gaim_notify_searchresults_new(); | |
1486 if((x = xmlnode_get_child_with_namespace(query, "x", "jabber:x:data"))) { | |
1487 xmlnode *reported; | |
1488 gaim_debug_info("jabber", "new-skool\n"); | |
1489 if((reported = xmlnode_get_child(x, "reported"))) { | |
1490 xmlnode *field = xmlnode_get_child(reported, "field"); | |
1491 while(field) { | |
1492 /* XXX keep track of this order, use it below */ | |
1493 const char *var = xmlnode_get_attrib(field, "var"); | |
1494 const char *label = xmlnode_get_attrib(field, "label"); | |
1495 if(var) { | |
1496 column = gaim_notify_searchresults_column_new(label ? label : var); | |
1497 gaim_notify_searchresults_column_add(results, column); | |
1498 } | |
1499 field = xmlnode_get_next_twin(field); | |
1500 } | |
1501 } | |
1502 item = xmlnode_get_child(x, "item"); | |
1503 while(item) { | |
1504 GList *row = NULL; | |
1505 field = xmlnode_get_child(item, "field"); | |
1506 while(field) { | |
13344 | 1507 xmlnode *valuenode = xmlnode_get_child(field, "value"); |
11675 | 1508 if(valuenode) { |
1509 char *value = xmlnode_get_data(valuenode); | |
1510 row = g_list_append(row, value); | |
1511 } | |
1512 field = xmlnode_get_next_twin(field); | |
1513 } | |
1514 gaim_notify_searchresults_row_add(results, row); | |
1515 | |
1516 item = xmlnode_get_next_twin(item); | |
1517 } | |
1518 } else { | |
1519 /* old skool */ | |
1520 gaim_debug_info("jabber", "old-skool\n"); | |
1521 | |
13571
02a8424191ea
[gaim-migrate @ 15950]
Richard Laager <rlaager@wiktel.com>
parents:
13545
diff
changeset
|
1522 column = gaim_notify_searchresults_column_new(_("JID")); |
11675 | 1523 gaim_notify_searchresults_column_add(results, column); |
13571
02a8424191ea
[gaim-migrate @ 15950]
Richard Laager <rlaager@wiktel.com>
parents:
13545
diff
changeset
|
1524 column = gaim_notify_searchresults_column_new(_("First Name")); |
11675 | 1525 gaim_notify_searchresults_column_add(results, column); |
13571
02a8424191ea
[gaim-migrate @ 15950]
Richard Laager <rlaager@wiktel.com>
parents:
13545
diff
changeset
|
1526 column = gaim_notify_searchresults_column_new(_("Last Name")); |
11675 | 1527 gaim_notify_searchresults_column_add(results, column); |
13571
02a8424191ea
[gaim-migrate @ 15950]
Richard Laager <rlaager@wiktel.com>
parents:
13545
diff
changeset
|
1528 column = gaim_notify_searchresults_column_new(_("Nickname")); |
11675 | 1529 gaim_notify_searchresults_column_add(results, column); |
13571
02a8424191ea
[gaim-migrate @ 15950]
Richard Laager <rlaager@wiktel.com>
parents:
13545
diff
changeset
|
1530 column = gaim_notify_searchresults_column_new(_("E-Mail")); |
11675 | 1531 gaim_notify_searchresults_column_add(results, column); |
1532 | |
1533 for(item = xmlnode_get_child(query, "item"); item; item = xmlnode_get_next_twin(item)) { | |
1534 const char *jid; | |
1535 xmlnode *node; | |
1536 GList *row = NULL; | |
1537 | |
1538 if(!(jid = xmlnode_get_attrib(item, "jid"))) | |
1539 continue; | |
1540 | |
1541 row = g_list_append(row, g_strdup(jid)); | |
1542 node = xmlnode_get_child(item, "first"); | |
1543 row = g_list_append(row, node ? xmlnode_get_data(node) : NULL); | |
1544 node = xmlnode_get_child(item, "last"); | |
1545 row = g_list_append(row, node ? xmlnode_get_data(node) : NULL); | |
1546 node = xmlnode_get_child(item, "nick"); | |
1547 row = g_list_append(row, node ? xmlnode_get_data(node) : NULL); | |
1548 node = xmlnode_get_child(item, "email"); | |
1549 row = g_list_append(row, node ? xmlnode_get_data(node) : NULL); | |
1550 gaim_debug_info("jabber", "row=%d\n", row); | |
1551 gaim_notify_searchresults_row_add(results, row); | |
1552 } | |
1553 } | |
1554 | |
12624
851b0bd7eb52
[gaim-migrate @ 14960]
Christopher O'Brien <siege@pidgin.im>
parents:
12467
diff
changeset
|
1555 gaim_notify_searchresults_button_add(results, GAIM_NOTIFY_BUTTON_ADD, |
11675 | 1556 user_search_result_add_buddy_cb); |
1557 | |
1558 gaim_notify_searchresults(js->gc, NULL, NULL, _("The following are the results of your search"), results, NULL, NULL); | |
1559 } | |
1560 | |
1561 static void user_search_x_data_cb(JabberStream *js, xmlnode *result, gpointer data) | |
1562 { | |
1563 xmlnode *query; | |
1564 JabberIq *iq; | |
13344 | 1565 char *dir_server = data; |
11675 | 1566 |
1567 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:search"); | |
1568 query = xmlnode_get_child(iq->node, "query"); | |
1569 | |
1570 xmlnode_insert_child(query, result); | |
1571 | |
1572 jabber_iq_set_callback(iq, user_search_result_cb, NULL); | |
13344 | 1573 xmlnode_set_attrib(iq->node, "to", dir_server); |
11675 | 1574 jabber_iq_send(iq); |
13344 | 1575 g_free(dir_server); |
11675 | 1576 } |
1577 | |
1578 struct user_search_info { | |
1579 JabberStream *js; | |
1580 char *directory_server; | |
1581 }; | |
1582 | |
1583 static void user_search_cancel_cb(struct user_search_info *usi, GaimRequestFields *fields) | |
1584 { | |
1585 g_free(usi->directory_server); | |
1586 g_free(usi); | |
1587 } | |
1588 | |
1589 static void user_search_cb(struct user_search_info *usi, GaimRequestFields *fields) | |
1590 { | |
1591 JabberStream *js = usi->js; | |
1592 JabberIq *iq; | |
1593 xmlnode *query; | |
1594 GList *groups, *flds; | |
1595 | |
1596 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:search"); | |
1597 query = xmlnode_get_child(iq->node, "query"); | |
1598 | |
1599 for(groups = gaim_request_fields_get_groups(fields); groups; groups = groups->next) { | |
1600 for(flds = gaim_request_field_group_get_fields(groups->data); | |
1601 flds; flds = flds->next) { | |
1602 GaimRequestField *field = flds->data; | |
1603 const char *id = gaim_request_field_get_id(field); | |
1604 const char *value = gaim_request_field_string_get_value(field); | |
1605 | |
1606 if(value && (!strcmp(id, "first") || !strcmp(id, "last") || !strcmp(id, "nick") || !strcmp(id, "email"))) { | |
1607 xmlnode *y = xmlnode_new_child(query, id); | |
1608 xmlnode_insert_data(y, value, -1); | |
1609 } | |
1610 } | |
1611 } | |
1612 | |
1613 jabber_iq_set_callback(iq, user_search_result_cb, NULL); | |
1614 xmlnode_set_attrib(iq->node, "to", usi->directory_server); | |
1615 jabber_iq_send(iq); | |
1616 | |
1617 g_free(usi->directory_server); | |
1618 g_free(usi); | |
1619 } | |
1620 | |
13616
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1621 #if 0 |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1622 /* 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
|
1623 |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1624 /* |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1625 * An incomplete list of server generated original language search |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1626 * comments for Jabber User Directories |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1627 * |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1628 * See discussion thread "Search comment for Jabber is not translatable" |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1629 * in gaim-i18n@lists.sourceforge.net (March 2006) |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1630 */ |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1631 static const char * jabber_user_dir_comments [] = { |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1632 /* current comment from Jabber User Directory users.jabber.org */ |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1633 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
|
1634 "Note: Each field supports wild card searches (%)"), |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1635 NULL |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1636 }; |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1637 #endif |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1638 |
11675 | 1639 static void user_search_fields_result_cb(JabberStream *js, xmlnode *packet, gpointer data) |
1640 { | |
1641 xmlnode *query, *x; | |
13344 | 1642 const char *from, *type; |
11675 | 1643 |
12284
ecd471d1eeec
[gaim-migrate @ 14588]
Etan Reisner <pidgin@unreliablesource.net>
parents:
11675
diff
changeset
|
1644 if(!(from = xmlnode_get_attrib(packet, "from"))) |
11675 | 1645 return; |
1646 | |
13344 | 1647 if(!(type = xmlnode_get_attrib(packet, "type")) || !strcmp(type, "error")) { |
13633
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1648 char *msg = jabber_parse_error(js, packet); |
13792 | 1649 |
13633
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1650 if(!msg) |
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1651 msg = g_strdup(_("Unknown error")); |
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1652 |
13617
513d0e06f35f
[gaim-migrate @ 16003]
Richard Laager <rlaager@wiktel.com>
parents:
13616
diff
changeset
|
1653 gaim_notify_error(js->gc, _("Directory Query Failed"), |
13633
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1654 _("Could not query the directory server."), msg); |
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1655 g_free(msg); |
c86c6f0505ea
[gaim-migrate @ 16031]
Richard Laager <rlaager@wiktel.com>
parents:
13618
diff
changeset
|
1656 |
13344 | 1657 return; |
1658 } | |
1659 | |
11675 | 1660 |
1661 if(!(query = xmlnode_get_child(packet, "query"))) | |
1662 return; | |
1663 | |
13329 | 1664 if((x = xmlnode_get_child_with_namespace(query, "x", "jabber:x:data"))) { |
13344 | 1665 jabber_x_data_request(js, x, user_search_x_data_cb, g_strdup(from)); |
11675 | 1666 return; |
1667 } else { | |
1668 struct user_search_info *usi; | |
1669 xmlnode *instnode; | |
13616
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1670 char *instructions = NULL; |
11675 | 1671 GaimRequestFields *fields; |
1672 GaimRequestFieldGroup *group; | |
1673 GaimRequestField *field; | |
1674 | |
1675 /* old skool */ | |
1676 fields = gaim_request_fields_new(); | |
1677 group = gaim_request_field_group_new(NULL); | |
1678 gaim_request_fields_add_group(fields, group); | |
1679 | |
1680 if((instnode = xmlnode_get_child(query, "instructions"))) | |
13573
0b2e4a5a8e79
[gaim-migrate @ 15952]
Richard Laager <rlaager@wiktel.com>
parents:
13571
diff
changeset
|
1681 { |
0b2e4a5a8e79
[gaim-migrate @ 15952]
Richard Laager <rlaager@wiktel.com>
parents:
13571
diff
changeset
|
1682 char *tmp = xmlnode_get_data(instnode); |
13792 | 1683 |
13616
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1684 if(tmp) |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1685 { |
13792 | 1686 /* Try to translate the message (see static message |
13616
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1687 list in jabber_user_dir_comments[]) */ |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1688 instructions = g_strdup_printf(_("Server Instructions: %s"), _(tmp)); |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1689 g_free(tmp); |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1690 } |
13573
0b2e4a5a8e79
[gaim-migrate @ 15952]
Richard Laager <rlaager@wiktel.com>
parents:
13571
diff
changeset
|
1691 } |
13792 | 1692 |
13616
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1693 if(!instructions) |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1694 { |
11675 | 1695 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
|
1696 "for any matching Jabber users.")); |
ee7f92a706ac
[gaim-migrate @ 16002]
Richard Laager <rlaager@wiktel.com>
parents:
13573
diff
changeset
|
1697 } |
11675 | 1698 |
1699 if(xmlnode_get_child(query, "first")) { | |
1700 field = gaim_request_field_string_new("first", _("First Name"), | |
1701 NULL, FALSE); | |
1702 gaim_request_field_group_add_field(group, field); | |
1703 } | |
1704 if(xmlnode_get_child(query, "last")) { | |
1705 field = gaim_request_field_string_new("last", _("Last Name"), | |
1706 NULL, FALSE); | |
1707 gaim_request_field_group_add_field(group, field); | |
1708 } | |
1709 if(xmlnode_get_child(query, "nick")) { | |
1710 field = gaim_request_field_string_new("nick", _("Nickname"), | |
1711 NULL, FALSE); | |
1712 gaim_request_field_group_add_field(group, field); | |
1713 } | |
1714 if(xmlnode_get_child(query, "email")) { | |
1715 field = gaim_request_field_string_new("email", _("E-Mail Address"), | |
1716 NULL, FALSE); | |
1717 gaim_request_field_group_add_field(group, field); | |
1718 } | |
1719 | |
1720 usi = g_new0(struct user_search_info, 1); | |
1721 usi->js = js; | |
1722 usi->directory_server = g_strdup(from); | |
1723 | |
1724 gaim_request_fields(js->gc, _("Search for Jabber users"), | |
1725 _("Search for Jabber users"), instructions, fields, | |
1726 _("Search"), G_CALLBACK(user_search_cb), | |
1727 _("Cancel"), G_CALLBACK(user_search_cancel_cb), usi); | |
1728 | |
1729 g_free(instructions); | |
1730 } | |
1731 } | |
1732 | |
1733 static void jabber_user_search_ok(JabberStream *js, const char *directory) | |
1734 { | |
1735 JabberIq *iq; | |
1736 | |
1737 /* XXX: should probably better validate the directory we're given */ | |
1738 if(!directory || !*directory) { | |
1739 gaim_notify_error(js->gc, _("Invalid Directory"), _("Invalid Directory"), NULL); | |
1740 return; | |
1741 } | |
1742 | |
1743 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:search"); | |
1744 xmlnode_set_attrib(iq->node, "to", directory); | |
1745 | |
1746 jabber_iq_set_callback(iq, user_search_fields_result_cb, NULL); | |
1747 | |
1748 jabber_iq_send(iq); | |
1749 } | |
1750 | |
1751 void jabber_user_search_begin(GaimPluginAction *action) | |
1752 { | |
1753 GaimConnection *gc = (GaimConnection *) action->context; | |
1754 JabberStream *js = gc->proto_data; | |
1755 | |
1756 gaim_request_input(gc, _("Enter a User Directory"), _("Enter a User Directory"), | |
1757 _("Select a user directory to search"), | |
1758 js->user_directories ? js->user_directories->data : "users.jabber.org", | |
1759 FALSE, FALSE, NULL, | |
1760 _("Search Directory"), GAIM_CALLBACK(jabber_user_search_ok), | |
1761 _("Cancel"), NULL, js); | |
1762 } | |
13792 | 1763 |
1764 | |
1765 |