Mercurial > pidgin
annotate src/protocols/jabber/jabber.c @ 6965:d4b4229bcd21
[gaim-migrate @ 7512]
fix sort by log size and sort by status, and allow dragging of entire contacts
into expanded contacts, like one would expect
committer: Tailor Script <tailor@pidgin.im>
author | Nathan Walp <nwalp@pidgin.im> |
---|---|
date | Thu, 25 Sep 2003 03:30:07 +0000 |
parents | c54699c55286 |
children | 083d1e4a9c78 |
rev | line source |
---|---|
2086 | 1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
2 /* | |
3 * gaim | |
4 * | |
5 * Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net> | |
6 * libfaim code copyright 1998, 1999 Adam Fritzler <afritz@auk.cx> | |
7 * | |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * This program is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 * GNU General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU General Public License | |
18 * along with this program; if not, write to the Free Software | |
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 * | |
21 */ | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
22 #include "internal.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
23 |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
24 #ifdef _WIN32 |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
25 # include "utsname.h" |
2086 | 26 #endif |
27 | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
28 #include "account.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
29 #include "accountopt.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
30 #include "conversation.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
31 #include "debug.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
32 #include "ft.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
33 #include "multi.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
34 #include "notify.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
35 #include "prpl.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
36 #include "request.h" |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
37 #include "util.h" |
6115
11bedb793a44
[gaim-migrate @ 6578]
Christian Hammond <chipx86@chipx86.com>
parents:
6106
diff
changeset
|
38 #include "html.h" |
6764 | 39 #include "sslconn.h" |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
40 |
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
41 /* XXX */ |
4608 | 42 #include "gaim.h" |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
43 |
2232
14e8978f86bb
[gaim-migrate @ 2242]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2231
diff
changeset
|
44 #ifdef MAX |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
45 # undef MAX |
2232
14e8978f86bb
[gaim-migrate @ 2242]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2231
diff
changeset
|
46 #endif |
14e8978f86bb
[gaim-migrate @ 2242]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2231
diff
changeset
|
47 #ifdef MIN |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
48 # undef MIN |
2232
14e8978f86bb
[gaim-migrate @ 2242]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2231
diff
changeset
|
49 #endif |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
50 |
2086 | 51 #include "jabber.h" |
52 #include "proxy.h" | |
53 | |
5205
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
54 static GaimPlugin *my_protocol = NULL; |
4249 | 55 |
2086 | 56 /* The priv member of gjconn's is a gaim_connection for now. */ |
5572 | 57 #define GJ_GC(x) ((GaimConnection *)(x)->priv) |
4249 | 58 /* Confused? That makes three of us. -Robot101 */ |
59 #define GC_GJ(x) ((gjconn)((struct jabber_data *)(x)->proto_data)->gjc) | |
2086 | 60 |
5894 | 61 #define JABBER_CONNECT_STEPS 5 |
5572 | 62 |
2086 | 63 #define IQID_AUTH "__AUTH__" |
64 | |
65 #define IQ_NONE -1 | |
66 #define IQ_AUTH 0 | |
67 #define IQ_ROSTER 1 | |
68 | |
3259 | 69 #define UC_AWAY (0x02 | UC_UNAVAILABLE) |
70 #define UC_CHAT 0x04 | |
71 #define UC_XA (0x08 | UC_UNAVAILABLE) | |
72 #define UC_DND (0x10 | UC_UNAVAILABLE) | |
73 #define UC_ERROR (0x20 | UC_UNAVAILABLE) | |
2086 | 74 |
4917 | 75 #define DEFAULT_SERVER "jabber.org" |
2086 | 76 #define DEFAULT_GROUPCHAT "conference.jabber.org" |
77 #define DEFAULT_PORT 5222 | |
78 | |
79 #define USEROPT_PORT 0 | |
4436 | 80 #define USEROPT_CONN_SERVER 1 |
2086 | 81 |
3311 | 82 #define JABBER_TYPING_NOTIFY_INT 15 /* Delay (in seconds) between sending typing notifications */ |
83 | |
4450 | 84 #define JABBER_KEEPALIVE_STRING " \t " |
85 | |
3074 | 86 /* |
87 * Note: "was_connected" may seem redundant, but it was needed and I | |
88 * didn't want to touch the Jabber state stuff not specific to Gaim. | |
89 */ | |
2086 | 90 typedef struct gjconn_struct { |
91 /* Core structure */ | |
92 pool p; /* Memory allocation pool */ | |
93 int state; /* Connection state flag */ | |
3074 | 94 int was_connected; /* We were once connected */ |
2086 | 95 int fd; /* Connection file descriptor */ |
96 jid user; /* User info */ | |
97 char *pass; /* User passwd */ | |
98 | |
99 /* Stream stuff */ | |
100 int id; /* id counter for jab_getid() function */ | |
101 char idbuf[9]; /* temporary storage for jab_getid() */ | |
102 char *sid; /* stream id from server, for digest auth */ | |
103 XML_Parser parser; /* Parser instance */ | |
104 xmlnode current; /* Current node in parsing instance.. */ | |
105 | |
106 /* Event callback ptrs */ | |
2956 | 107 void (*on_state)(struct gjconn_struct *gjc, int state); |
108 void (*on_packet)(struct gjconn_struct *gjc, jpacket p); | |
109 | |
110 GHashTable *queries; /* query tracker */ | |
2086 | 111 |
112 void *priv; | |
113 | |
6764 | 114 GaimSslConnection *gsc; |
115 | |
2086 | 116 } *gjconn, gjconn_struct; |
117 | |
2956 | 118 typedef void (*gjconn_state_h)(gjconn gjc, int state); |
119 typedef void (*gjconn_packet_h)(gjconn gjc, jpacket p); | |
2086 | 120 |
121 static gjconn gjab_new(char *user, char *pass, void *priv); | |
2956 | 122 static void gjab_delete(gjconn gjc); |
123 static void gjab_state_handler(gjconn gjc, gjconn_state_h h); | |
124 static void gjab_packet_handler(gjconn gjc, gjconn_packet_h h); | |
125 static void gjab_start(gjconn gjc); | |
126 static void gjab_stop(gjconn gjc); | |
2086 | 127 /* |
2956 | 128 static int gjab_getfd(gjconn gjc); |
129 static jid gjab_getjid(gjconn gjc); | |
130 static char *gjab_getsid(gjconn gjc); | |
2086 | 131 */ |
2956 | 132 static char *gjab_getid(gjconn gjc); |
133 static void gjab_send(gjconn gjc, xmlnode x); | |
134 static void gjab_send_raw(gjconn gjc, const char *str); | |
135 static void gjab_recv(gjconn gjc); | |
136 static void gjab_auth(gjconn gjc); | |
137 | |
138 /* | |
139 * It is *this* to which we point the gaim_connection proto_data | |
140 */ | |
2086 | 141 struct jabber_data { |
2956 | 142 gjconn gjc; |
2086 | 143 gboolean did_import; |
2956 | 144 GSList *chats; |
2086 | 145 time_t idle; |
3311 | 146 GHashTable *buddies; |
3630 | 147 GSList *file_transfers; |
2086 | 148 }; |
149 | |
2956 | 150 /* |
3340 | 151 * Used in jabber_buddy_data.invisible, below |
152 */ | |
153 #define JABBER_NOT_INVIS 0x00 | |
154 #define JABBER_SERV_INVIS 0x01 /* Invisible set on server */ | |
155 #define JABBER_BUD_INVIS 0x02 /* Invisible set on buddy */ | |
156 | |
157 /* | |
4927 | 158 * Used in jabber_buddy_data.subscription, below |
159 */ | |
160 #define JABBER_SUB_NONE 0x0 | |
161 #define JABBER_SUB_PENDING 0x1 | |
162 #define JABBER_SUB_TO 0x2 | |
163 #define JABBER_SUB_FROM 0x4 | |
164 #define JABBER_SUB_BOTH (JABBER_SUB_TO | JABBER_SUB_FROM) | |
165 | |
166 | |
167 /* | |
3311 | 168 * It is *this* to which we point the buddy proto_data |
169 */ | |
170 struct jabber_buddy_data { | |
171 GSList *resources; | |
172 char *error_msg; | |
3340 | 173 unsigned invisible; /* We've set presence type invisible for this buddy */ |
4927 | 174 unsigned subscription; /* subscription type for this buddy */ |
3311 | 175 }; |
176 | |
177 /* | |
178 * per-resource info | |
179 */ | |
180 typedef struct jabber_resource_info { | |
3770 | 181 char *name; |
3311 | 182 int priority; |
183 int state; | |
184 char *away_msg; | |
185 char *thread_id; | |
186 gboolean has_composing; | |
5093 | 187 gboolean has_xhtml; |
3311 | 188 } *jab_res_info; |
189 | |
190 /* | |
191 * For our own jid handling | |
192 * | |
193 * We do our own so we can cleanly parse buddy names | |
194 * (user@server/resource) and rid ourselves of the | |
195 * struct when we're done with it. The Jabber lib | |
196 * structs last the life of the pool--we frequently | |
197 * don't want that. | |
198 * | |
199 * We use the real jid structs so we can make use of | |
200 * jid_safe(), jid_cmp() and some others. | |
201 * | |
202 * BE CAREFUL using the Jabber lib routines. | |
203 * Many of them assume pool use and are not | |
204 * amenable to use with our own! | |
205 * | |
206 * We give them special names so we know, throughout | |
207 * the code, that they're not alloc'd out of pool | |
208 * memory and we can, and must, dispose of them when | |
209 * we're done with 'em. | |
210 */ | |
211 #define gaim_jid_struct jid_struct | |
212 typedef struct gaim_jid_struct *gaim_jid; | |
213 | |
214 /* | |
2956 | 215 * Jabber "chat group" info. Pointers to these go in jabber_data |
216 * pending and existing chats lists. | |
217 */ | |
2086 | 218 struct jabber_chat { |
3311 | 219 gaim_jid gjid; |
5572 | 220 GaimConnection *gc; |
5679 | 221 GaimConversation *b; |
2086 | 222 int id; |
2956 | 223 int state; |
2086 | 224 }; |
225 | |
2956 | 226 /* |
227 * Jabber chat states... | |
228 * | |
229 * Note: due to a bug in one version of the Jabber server, subscriptions | |
230 * to chat groups aren't (always?) properly removed at the server. The | |
231 * result is clients receive Jabber "presence" notifications for JIDs | |
232 * they no longer care about. The problem with such vestigial notifies is | |
233 * that we really have no way of telling if it's vestigial or if it's a | |
234 * valid "buddy" presence notification. So we keep jabber_chat structs | |
235 * around after leaving a chat group and simply mark them "closed." That | |
236 * way we can test for such errant presence notifications. I.e.: if we | |
237 * get a presence notfication from a JID that matches a chat group JID, | |
238 * we disregard it. | |
239 */ | |
240 #define JCS_PENDING 1 /* pending */ | |
241 #define JCS_ACTIVE 2 /* active */ | |
242 #define JCS_CLOSED 3 /* closed */ | |
243 | |
244 | |
245 #define STATE_EVT(arg) if(gjc->on_state) { (gjc->on_state)(gjc, (arg) ); } | |
246 | |
247 static void jabber_handlevcard(gjconn, xmlnode, char *); | |
2086 | 248 |
3630 | 249 static char *jabber_normalize(const char *s); |
250 | |
2086 | 251 static char *create_valid_jid(const char *given, char *server, char *resource) |
252 { | |
253 char *valid; | |
4927 | 254 char *tmp; |
255 | |
256 if (!(tmp = strchr(given, '@'))) | |
2086 | 257 valid = g_strdup_printf("%s@%s/%s", given, server, resource); |
4927 | 258 else if (!strchr(tmp, '/')) |
2086 | 259 valid = g_strdup_printf("%s/%s", given, resource); |
260 else | |
261 valid = g_strdup(given); | |
262 | |
263 return valid; | |
264 } | |
265 | |
4915 | 266 |
3311 | 267 /* |
268 * Dispose of a gaim_jid_struct | |
269 */ | |
270 static void gaim_jid_free(gaim_jid gjid) | |
271 { | |
272 if(gjid) { | |
273 if(gjid->resource) | |
274 free(gjid->resource); | |
275 if(gjid->user) | |
276 free(gjid->user); | |
277 if(gjid->server) | |
278 free(gjid->server); | |
279 if(gjid->full) | |
280 free(gjid->full); | |
281 free(gjid); | |
282 } | |
283 } | |
284 | |
285 /* | |
286 * Create a new gjid struct | |
287 * | |
288 * Unlike jid_new(), also creates "full." | |
289 * | |
290 * Shamelessly copied, in part, from jid.c: jid_new() | |
291 * | |
292 * Caller is responsible for freeing the space allocated by this via | |
293 * gaim_jid_free(). | |
294 * | |
295 * JFIXME: Has a local declaration for jid.c:jid_safe(). I've put in a | |
296 * request to have that added to libjabber's lib.h file. (JSeymour) | |
297 */ | |
298 static gaim_jid gaim_jid_new(char *name) | |
299 { | |
300 extern jid jid_safe(jid); /* *retch* */ | |
301 | |
302 gaim_jid gjid = NULL; | |
303 | |
304 if(name && strlen(name)) { | |
305 char *server, *resource, *type, *str; | |
306 int full_len = 0; | |
307 | |
308 /* user@server/resource */ | |
309 | |
310 str = strdup(name); /* we mangle a copy */ | |
311 | |
312 gjid = calloc(1, sizeof(struct gaim_jid_struct)); | |
313 | |
314 if((resource = strstr(str, "/")) != NULL) { | |
315 *resource = '\0'; | |
316 ++resource; | |
317 if((full_len = strlen(resource)) > 0) { | |
318 gjid->resource = strdup(resource); | |
319 ++full_len; /* for later "/" addition */ | |
320 } | |
321 } else { | |
322 resource = str + strlen(str); /* point to end */ | |
323 } | |
324 | |
325 type = strstr(str, ":"); | |
326 if(type != NULL && type < resource) { | |
327 *type = '\0'; | |
328 ++type; | |
329 str = type; /* ignore the type: prefix */ | |
330 } | |
331 | |
332 server = strstr(str, "@"); | |
333 | |
334 /* | |
335 * if there's no @, it's just the server address | |
336 */ | |
337 if(server == NULL || server > resource) { | |
338 gjid->server = strdup(str); | |
339 full_len += strlen(str); | |
340 } else { | |
341 *server = '\0'; | |
342 ++server; | |
343 gjid->server = strdup(server); | |
344 full_len += strlen(server) + 1; /* account for later "@" */ | |
345 if(strlen(str) > 0) { | |
346 gjid->user = strdup(str); | |
347 full_len += strlen(str); | |
348 } | |
349 } | |
350 | |
351 free(str); | |
352 | |
353 if(!jid_safe(gjid)) { | |
354 gaim_jid_free(gjid); | |
355 gjid = NULL; | |
356 } else { | |
357 if(full_len) { | |
358 char *s = gjid->full = malloc(++full_len); | |
359 | |
360 if(gjid->user) { | |
361 strcpy(s, gjid->user); | |
362 s += strlen(gjid->user); | |
363 } | |
364 if(gjid->server) { | |
365 if(s > gjid->full) | |
366 *(s++) = '@'; | |
367 strcpy(s, gjid->server); | |
368 s += strlen(gjid->server); | |
369 } | |
370 if(gjid->resource) { | |
371 *(s++) = '/'; | |
372 strcpy(s, gjid->resource); | |
373 } | |
374 } | |
375 } | |
376 } | |
377 | |
378 return gjid; | |
379 } | |
380 | |
381 /* | |
382 * Get a "username@server" from unadorned "username" | |
383 * | |
384 * If there's no "@server" part and "who" doesn't match the | |
385 * gjconn server (which would indicate that "who" *is* the | |
386 * server in case of server messages), the gjconn server is | |
387 * appended. | |
388 * | |
389 * If incl_resource is TRUE (non-0), the returned string | |
390 * includes the "/resource" part (if it exists), otherwise not. | |
391 * | |
392 * Allocates space for returned string. Caller is | |
393 * responsible for freeing it with g_free(). | |
394 * | |
395 * If "gjid" is non-null, sets that as well. Caller is | |
396 * reponsible for freeing that via gaim_jid_free() when done | |
397 * with it. | |
398 */ | |
3466 | 399 static gchar *get_realwho(gjconn gjc, const char *who, int incl_resource, gaim_jid *gjid) |
3311 | 400 { |
401 gaim_jid my_gjid; | |
402 gchar *my_who; | |
403 gchar *realwho = NULL; | |
404 | |
405 if(!(who && who[0])) { | |
406 return NULL; | |
407 } | |
408 | |
409 /* | |
410 * Bare username and "username" not the server itself? | |
411 */ | |
412 if(!strchr(who, '@') && strcasecmp(who, gjc->user->server)) { | |
413 my_who = g_strdup_printf("%s@%s", who, gjc->user->server); | |
414 } else { | |
415 my_who = g_strdup(who); | |
416 } | |
417 | |
418 if((my_gjid = gaim_jid_new(my_who)) != NULL) { | |
419 /* | |
420 * If there's no "user" part, "who" was just the server or perhaps a transport (?) | |
421 */ | |
422 if(my_gjid->user) { | |
423 /* | |
424 * Include "/resource" bit? | |
425 */ | |
426 if(incl_resource) { | |
427 realwho = g_strdup(my_gjid->full); | |
428 } else { | |
429 realwho = g_strdup_printf("%s@%s", my_gjid->user, my_gjid->server); | |
430 } | |
431 } else { | |
432 realwho = g_strdup(my_gjid->server); | |
433 } | |
434 } | |
435 | |
436 g_free(my_who); | |
437 | |
438 if(gjid) { | |
439 *gjid = my_gjid; | |
440 } else { | |
441 gaim_jid_free(my_gjid); | |
442 } | |
443 | |
444 return realwho; | |
445 } | |
446 | |
2086 | 447 static gjconn gjab_new(char *user, char *pass, void *priv) |
448 { | |
449 pool p; | |
2956 | 450 gjconn gjc; |
2086 | 451 |
452 if (!user) | |
453 return (NULL); | |
454 | |
455 p = pool_new(); | |
456 if (!p) | |
457 return (NULL); | |
2956 | 458 gjc = pmalloc_x(p, sizeof(gjconn_struct), 0); |
459 if (!gjc) { | |
460 pool_free(p); /* no need for this anymore! */ | |
2086 | 461 return (NULL); |
2956 | 462 } |
463 gjc->p = p; | |
464 | |
3236 | 465 if((gjc->user = jid_new(p, user)) == NULL) { |
466 pool_free(p); /* no need for this anymore! */ | |
467 return (NULL); | |
468 } | |
3257 | 469 |
470 gjc->pass = strdup(pass); | |
2956 | 471 |
472 gjc->state = JCONN_STATE_OFF; | |
3074 | 473 gjc->was_connected = 0; |
2956 | 474 gjc->id = 1; |
475 gjc->fd = -1; | |
476 | |
477 gjc->priv = priv; | |
478 | |
479 return gjc; | |
2086 | 480 } |
481 | |
2956 | 482 static void gjab_delete(gjconn gjc) |
2086 | 483 { |
2956 | 484 if (!gjc) |
2086 | 485 return; |
486 | |
2956 | 487 gjab_stop(gjc); |
3257 | 488 free(gjc->pass); |
2956 | 489 pool_free(gjc->p); |
2086 | 490 } |
491 | |
2956 | 492 static void gjab_state_handler(gjconn gjc, gjconn_state_h h) |
2086 | 493 { |
2956 | 494 if (!gjc) |
2086 | 495 return; |
496 | |
2956 | 497 gjc->on_state = h; |
2086 | 498 } |
499 | |
2956 | 500 static void gjab_packet_handler(gjconn gjc, gjconn_packet_h h) |
2086 | 501 { |
2956 | 502 if (!gjc) |
2086 | 503 return; |
504 | |
2956 | 505 gjc->on_packet = h; |
2086 | 506 } |
507 | |
2956 | 508 static void gjab_stop(gjconn gjc) |
2086 | 509 { |
2956 | 510 if (!gjc || gjc->state == JCONN_STATE_OFF) |
2086 | 511 return; |
512 | |
2956 | 513 gjab_send_raw(gjc, "</stream:stream>"); |
514 gjc->state = JCONN_STATE_OFF; | |
3074 | 515 gjc->was_connected = 0; |
6764 | 516 if(gjc->gsc) |
517 gaim_ssl_close(gjc->gsc); | |
518 else | |
519 close(gjc->fd); | |
2956 | 520 gjc->fd = -1; |
521 XML_ParserFree(gjc->parser); | |
522 gjc->parser = NULL; | |
2086 | 523 } |
524 | |
525 /* | |
2956 | 526 static int gjab_getfd(gjconn gjc) |
2086 | 527 { |
2956 | 528 if (gjc) |
529 return gjc->fd; | |
2086 | 530 else |
531 return -1; | |
532 } | |
533 | |
2956 | 534 static jid gjab_getjid(gjconn gjc) |
2086 | 535 { |
2956 | 536 if (gjc) |
537 return (gjc->user); | |
2086 | 538 else |
539 return NULL; | |
540 } | |
541 | |
2956 | 542 static char *gjab_getsid(gjconn gjc) |
2086 | 543 { |
2956 | 544 if (gjc) |
545 return (gjc->sid); | |
2086 | 546 else |
547 return NULL; | |
548 } | |
549 */ | |
550 | |
2956 | 551 static char *gjab_getid(gjconn gjc) |
2086 | 552 { |
2956 | 553 snprintf(gjc->idbuf, 8, "%d", gjc->id++); |
554 return &gjc->idbuf[0]; | |
2086 | 555 } |
556 | |
2956 | 557 static void gjab_send(gjconn gjc, xmlnode x) |
2086 | 558 { |
2956 | 559 if (gjc && gjc->state != JCONN_STATE_OFF) { |
2086 | 560 char *buf = xmlnode2str(x); |
6076 | 561 if (buf) { |
6764 | 562 if(gjc->gsc) { |
563 if(gaim_ssl_write(gjc->gsc, buf, strlen(buf)) < 0) { | |
564 gaim_connection_error(GJ_GC(gjc), _("Write error")); | |
565 } else { | |
566 gaim_debug(GAIM_DEBUG_MISC, "jabber", "gjab_send (ssl): %s\n", buf); | |
567 } | |
568 } else { | |
3630 | 569 #ifndef _WIN32 |
6764 | 570 if(write(gjc->fd, buf, strlen(buf)) < 0) { |
3630 | 571 #else |
6764 | 572 if(send(gjc->fd, buf, strlen(buf), 0) < 0) { |
3630 | 573 #endif |
6764 | 574 gaim_connection_error(GJ_GC(gjc), _("Write error")); |
575 } else { | |
576 gaim_debug(GAIM_DEBUG_MISC, "jabber", "gjab_send: %s\n", buf); | |
577 } | |
6076 | 578 } |
579 } | |
2086 | 580 } |
581 } | |
582 | |
2956 | 583 static void gjab_send_raw(gjconn gjc, const char *str) |
2086 | 584 { |
2956 | 585 if (gjc && gjc->state != JCONN_STATE_OFF) { |
586 /* | |
587 * JFIXME: No error detection?!?! | |
588 */ | |
6764 | 589 if(gjc->gsc) { |
590 if(gaim_ssl_write(gjc->gsc, str, strlen(str)) < 0) { | |
591 gaim_connection_error(GJ_GC(gjc), _("Write error")); | |
592 } else { | |
593 gaim_debug(GAIM_DEBUG_MISC, "jabber", "gjab_send_raw (ssl): %s\n", str); | |
594 } | |
595 } else { | |
3630 | 596 #ifndef _WIN32 |
6764 | 597 if(write(gjc->fd, str, strlen(str)) < 0) { |
3630 | 598 #else |
6764 | 599 if(send(gjc->fd, str, strlen(str), 0) < 0) { |
3630 | 600 #endif |
6764 | 601 gaim_connection_error(GJ_GC(gjc), _("Write error")); |
602 } | |
603 /* printing keepalives to the debug window is really annoying */ | |
604 if(strcmp(str, JABBER_KEEPALIVE_STRING)) | |
605 gaim_debug(GAIM_DEBUG_MISC, "jabber", "gjab_send_raw: %s\n", str); | |
2956 | 606 } |
2086 | 607 } |
608 } | |
609 | |
2956 | 610 static void gjab_reqroster(gjconn gjc) |
2086 | 611 { |
612 xmlnode x; | |
613 | |
614 x = jutil_iqnew(JPACKET__GET, NS_ROSTER); | |
2956 | 615 xmlnode_put_attrib(x, "id", gjab_getid(gjc)); |
616 | |
617 gjab_send(gjc, x); | |
2086 | 618 xmlnode_free(x); |
619 } | |
620 | |
2956 | 621 static void gjab_reqauth(gjconn gjc) |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
622 { |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
623 xmlnode x, y, z; |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
624 char *user; |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
625 |
2956 | 626 if (!gjc) |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
627 return; |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
628 |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
629 x = jutil_iqnew(JPACKET__GET, NS_AUTH); |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
630 xmlnode_put_attrib(x, "id", IQID_AUTH); |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
631 y = xmlnode_get_tag(x, "query"); |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
632 |
2956 | 633 user = gjc->user->user; |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
634 |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
635 if (user) { |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
636 z = xmlnode_insert_tag(y, "username"); |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
637 xmlnode_insert_cdata(z, user, -1); |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
638 } |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
639 |
2956 | 640 gjab_send(gjc, x); |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
641 xmlnode_free(x); |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
642 } |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
643 |
2956 | 644 static void gjab_auth(gjconn gjc) |
2086 | 645 { |
646 xmlnode x, y, z; | |
647 char *hash, *user; | |
648 | |
2956 | 649 if (!gjc) |
2086 | 650 return; |
651 | |
652 x = jutil_iqnew(JPACKET__SET, NS_AUTH); | |
653 xmlnode_put_attrib(x, "id", IQID_AUTH); | |
654 y = xmlnode_get_tag(x, "query"); | |
655 | |
2956 | 656 user = gjc->user->user; |
2086 | 657 |
658 if (user) { | |
659 z = xmlnode_insert_tag(y, "username"); | |
660 xmlnode_insert_cdata(z, user, -1); | |
661 } | |
662 | |
663 z = xmlnode_insert_tag(y, "resource"); | |
2956 | 664 xmlnode_insert_cdata(z, gjc->user->resource, -1); |
665 | |
666 if (gjc->sid) { | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
667 gaim_debug(GAIM_DEBUG_MISC, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
668 "digest authentication (sid %s)\n", gjc->sid); |
2086 | 669 z = xmlnode_insert_tag(y, "digest"); |
2956 | 670 hash = pmalloc(x->p, strlen(gjc->sid) + strlen(gjc->pass) + 1); |
671 strcpy(hash, gjc->sid); | |
672 strcat(hash, gjc->pass); | |
2086 | 673 hash = shahash(hash); |
674 xmlnode_insert_cdata(z, hash, 40); | |
675 } else { | |
676 z = xmlnode_insert_tag(y, "password"); | |
2956 | 677 xmlnode_insert_cdata(z, gjc->pass, -1); |
2086 | 678 } |
679 | |
2956 | 680 gjab_send(gjc, x); |
2086 | 681 xmlnode_free(x); |
682 | |
683 return; | |
684 } | |
685 | |
2956 | 686 static void gjab_recv(gjconn gjc) |
2086 | 687 { |
688 static char buf[4096]; | |
689 int len; | |
690 | |
2956 | 691 if (!gjc || gjc->state == JCONN_STATE_OFF) |
2086 | 692 return; |
3630 | 693 #ifndef _WIN32 |
3234 | 694 if ((len = read(gjc->fd, buf, sizeof(buf) - 1)) > 0) { |
3630 | 695 #else |
696 if ((len = recv(gjc->fd, buf, sizeof(buf) - 1, 0)) > 0) { | |
697 #endif | |
2086 | 698 buf[len] = '\0'; |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
699 gaim_debug(GAIM_DEBUG_MISC, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
700 "input (len %d): %s\n", len, buf); |
2956 | 701 XML_Parse(gjc->parser, buf, len, 0); |
3105 | 702 } else if (len < 0 || errno != EAGAIN) { |
2086 | 703 STATE_EVT(JCONN_STATE_OFF) |
704 } | |
705 } | |
706 | |
6764 | 707 static void gjab_ssl_recv(gpointer data, GaimSslConnection *gsc, |
708 GaimInputCondition cond) | |
709 { | |
710 static char buf[4096]; | |
711 int len; | |
712 GaimConnection *gc = data; | |
6768 | 713 struct jabber_data *jd; |
714 gjconn gjc; | |
715 | |
716 | |
717 if (!g_list_find(gaim_connections_get_all(), gc)) { | |
718 gaim_ssl_close(gsc); | |
719 return; | |
720 } | |
721 | |
722 jd = gc->proto_data; | |
723 gjc= jd->gjc; | |
6764 | 724 |
725 if (!gjc || gjc->state == JCONN_STATE_OFF) | |
726 return; | |
727 | |
728 if((len = gaim_ssl_read(gsc, buf, sizeof(buf) -1)) > 0) { | |
729 buf[len] = '\0'; | |
730 gaim_debug(GAIM_DEBUG_MISC, "jabber", | |
731 "input (ssl) (len %d): %s\n", len, buf); | |
732 XML_Parse(gjc->parser, buf, len, 0); | |
733 } else if(len < 0) { | |
734 STATE_EVT(JCONN_STATE_OFF) | |
735 } | |
736 } | |
737 | |
2086 | 738 static void startElement(void *userdata, const char *name, const char **attribs) |
739 { | |
740 xmlnode x; | |
2956 | 741 gjconn gjc = (gjconn) userdata; |
742 | |
743 if (gjc->current) { | |
2086 | 744 /* Append the node to the current one */ |
2956 | 745 x = xmlnode_insert_tag(gjc->current, name); |
2086 | 746 xmlnode_put_expat_attribs(x, attribs); |
747 | |
2956 | 748 gjc->current = x; |
2086 | 749 } else { |
750 x = xmlnode_new_tag(name); | |
751 xmlnode_put_expat_attribs(x, attribs); | |
752 if (strcmp(name, "stream:stream") == 0) { | |
753 /* special case: name == stream:stream */ | |
754 /* id attrib of stream is stored for digest auth */ | |
2956 | 755 gjc->sid = g_strdup(xmlnode_get_attrib(x, "id")); |
6638 | 756 gjc->state = JCONN_STATE_ON; |
757 STATE_EVT(JCONN_STATE_ON); | |
2635
8c75e59e4bdf
[gaim-migrate @ 2648]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2607
diff
changeset
|
758 xmlnode_free(x); |
2086 | 759 } else { |
2956 | 760 gjc->current = x; |
2086 | 761 } |
762 } | |
763 } | |
764 | |
765 static void endElement(void *userdata, const char *name) | |
766 { | |
2956 | 767 gjconn gjc = (gjconn) userdata; |
2086 | 768 xmlnode x; |
769 jpacket p; | |
770 | |
2956 | 771 if (gjc->current == NULL) { |
2086 | 772 /* we got </stream:stream> */ |
773 STATE_EVT(JCONN_STATE_OFF) | |
774 return; | |
775 } | |
776 | |
2956 | 777 x = xmlnode_get_parent(gjc->current); |
2086 | 778 |
779 if (!x) { | |
780 /* it is time to fire the event */ | |
2956 | 781 p = jpacket_new(gjc->current); |
782 | |
783 if (gjc->on_packet) | |
784 (gjc->on_packet) (gjc, p); | |
2086 | 785 else |
2956 | 786 xmlnode_free(gjc->current); |
2086 | 787 } |
788 | |
2956 | 789 gjc->current = x; |
2086 | 790 } |
791 | |
2090
b66aca8e8dce
[gaim-migrate @ 2100]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
792 static void jabber_callback(gpointer data, gint source, GaimInputCondition condition) |
2086 | 793 { |
5572 | 794 GaimConnection *gc = data; |
2086 | 795 struct jabber_data *jd = (struct jabber_data *)gc->proto_data; |
796 | |
2956 | 797 gjab_recv(jd->gjc); |
2086 | 798 } |
799 | |
800 static void charData(void *userdata, const char *s, int slen) | |
801 { | |
2956 | 802 gjconn gjc = (gjconn) userdata; |
803 | |
804 if (gjc->current) | |
805 xmlnode_insert_cdata(gjc->current, s, slen); | |
2086 | 806 } |
807 | |
6764 | 808 |
809 static void gjab_start_stream(gjconn gjc) | |
2086 | 810 { |
811 xmlnode x; | |
812 char *t, *t2; | |
6764 | 813 |
814 gjc->state = JCONN_STATE_CONNECTED; | |
815 STATE_EVT(JCONN_STATE_CONNECTED) | |
816 | |
817 /* start stream */ | |
818 x = jutil_header(NS_CLIENT, gjc->user->server); | |
819 t = xmlnode2str(x); | |
820 /* this is ugly, we can create the string here instead of jutil_header */ | |
821 /* what do you think about it? -madcat */ | |
822 t2 = strstr(t, "/>"); | |
823 *t2++ = '>'; | |
824 *t2 = '\0'; | |
825 gjab_send_raw(gjc, "<?xml version='1.0'?>"); | |
826 gjab_send_raw(gjc, t); | |
827 xmlnode_free(x); | |
828 } | |
829 | |
830 static void gjab_ssl_connected(gpointer data, GaimSslConnection *gsc, | |
831 GaimInputCondition cond) | |
832 { | |
833 GaimConnection *gc = data; | |
834 struct jabber_data *jd; | |
835 gjconn gjc; | |
836 | |
837 if (!g_list_find(gaim_connections_get_all(), gc)) { | |
838 gaim_ssl_close(gsc); | |
839 return; | |
840 } | |
841 | |
842 jd = gc->proto_data; | |
843 gjc = jd->gjc; | |
844 | |
845 gjab_start_stream(gjc); | |
846 | |
847 /* this seems wrong, but... */ | |
848 | |
849 gaim_ssl_input_add(gsc, gjab_ssl_recv, gc); | |
850 } | |
851 | |
852 static void gjab_connected(gpointer data, gint source, GaimInputCondition cond) | |
853 { | |
5572 | 854 GaimConnection *gc = data; |
2086 | 855 struct jabber_data *jd; |
2956 | 856 gjconn gjc; |
2086 | 857 |
5578
847ad796326d
[gaim-migrate @ 5982]
Christian Hammond <chipx86@chipx86.com>
parents:
5572
diff
changeset
|
858 if (!g_list_find(gaim_connections_get_all(), gc)) { |
2086 | 859 close(source); |
860 return; | |
861 } | |
862 | |
863 jd = gc->proto_data; | |
2956 | 864 gjc = jd->gjc; |
865 | |
4366 | 866 gjc->fd = source; |
2300
d2686f757d6e
[gaim-migrate @ 2310]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2289
diff
changeset
|
867 |
2086 | 868 if (source == -1) { |
869 STATE_EVT(JCONN_STATE_OFF) | |
870 return; | |
871 } | |
872 | |
6764 | 873 gjab_start_stream(gjc); |
874 | |
2956 | 875 gc->inpa = gaim_input_add(gjc->fd, GAIM_INPUT_READ, jabber_callback, gc); |
2086 | 876 } |
877 | |
2956 | 878 static void gjab_start(gjconn gjc) |
2086 | 879 { |
5572 | 880 GaimAccount *account; |
4366 | 881 int port, rc; |
5613 | 882 const char *connect_server; |
5572 | 883 const char *server; |
2086 | 884 |
2956 | 885 if (!gjc || gjc->state != JCONN_STATE_OFF) |
2086 | 886 return; |
887 | |
4491 | 888 account = GJ_GC(gjc)->account; |
5572 | 889 port = gaim_account_get_int(account, "port", DEFAULT_PORT); |
5613 | 890 connect_server = gaim_account_get_string(account, "connect_server", ""); |
891 server = connect_server[0] ? connect_server : gjc->user->server; | |
892 | |
2086 | 893 |
2956 | 894 gjc->parser = XML_ParserCreate(NULL); |
895 XML_SetUserData(gjc->parser, (void *)gjc); | |
896 XML_SetElementHandler(gjc->parser, startElement, endElement); | |
897 XML_SetCharacterDataHandler(gjc->parser, charData); | |
898 | |
6880 | 899 if(gaim_account_get_bool(account, "old_ssl", FALSE) |
6764 | 900 && gaim_ssl_is_supported()) { |
901 gjc->gsc = gaim_ssl_connect(account, server, port, | |
902 gjab_ssl_connected, GJ_GC(gjc)); | |
903 } | |
904 | |
905 if(!gjc->gsc) { | |
906 rc = gaim_proxy_connect(account, server, port, gjab_connected, | |
907 GJ_GC(gjc)); | |
908 if (!account->gc || (rc != 0)) { | |
909 STATE_EVT(JCONN_STATE_OFF) | |
910 return; | |
911 } | |
2086 | 912 } |
913 } | |
914 | |
2956 | 915 /* |
916 * Find chat by chat group name | |
917 */ | |
5679 | 918 static GaimConversation *find_chat(GaimConnection *gc, char *name) |
2086 | 919 { |
920 GSList *bcs = gc->buddy_chats; | |
5679 | 921 GaimConversation *b = NULL; |
2086 | 922 char *chat = g_strdup(normalize(name)); |
923 | |
924 while (bcs) { | |
925 b = bcs->data; | |
926 if (!strcasecmp(normalize(b->name), chat)) | |
927 break; | |
928 b = NULL; | |
929 bcs = bcs->next; | |
930 } | |
931 | |
932 g_free(chat); | |
933 return b; | |
934 } | |
935 | |
2956 | 936 /* |
937 * Find chat by "chat id" | |
938 * | |
939 * Returns: 0 on success and jabber_chat pointer set | |
940 * or -EINVAL on error and jabber_chat pointer is | |
941 * undefined. | |
942 * | |
943 * TBD: Slogging through the buddy_chats list seems | |
944 * redundant since the chat i.d. is mirrored in the | |
945 * jabber_chat struct list. But that's the way it | |
946 * was, so that's the way I'm leaving it--for now. | |
947 */ | |
5572 | 948 static int jabber_find_chat_by_convo_id(GaimConnection *gc, int id, struct jabber_chat **jc) |
2086 | 949 { |
2956 | 950 GSList *bcs = gc->buddy_chats; |
5679 | 951 GaimConversation *b = NULL; |
2956 | 952 struct jabber_data *jd = gc->proto_data; |
953 | |
954 *jc = NULL; | |
955 | |
956 while(bcs != NULL) { | |
957 b = bcs->data; | |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
958 if (id == gaim_chat_get_id(GAIM_CHAT(b))) |
2956 | 959 break; |
960 bcs = bcs->next; | |
961 } | |
962 | |
963 if (bcs != NULL) { | |
964 bcs = jd->chats; | |
965 while (bcs != NULL) { | |
966 *jc = bcs->data; | |
967 if ((*jc)->state == JCS_ACTIVE && (*jc)->b == b) | |
968 break; | |
969 bcs = bcs->next; | |
970 } | |
971 } | |
972 | |
973 return(bcs == NULL? -EINVAL : 0); | |
974 } | |
975 | |
976 /* | |
977 * Find any chat | |
978 */ | |
5572 | 979 static struct jabber_chat *find_any_chat(GaimConnection *gc, jid chat) |
2956 | 980 { |
981 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; | |
2086 | 982 struct jabber_chat *jc = NULL; |
983 | |
2956 | 984 while (jcs) { |
985 jc = jcs->data; | |
3311 | 986 if (!jid_cmpx(chat, jc->gjid, JID_USER | JID_SERVER)) |
2086 | 987 break; |
988 jc = NULL; | |
2956 | 989 jcs = jcs->next; |
2086 | 990 } |
991 | |
992 return jc; | |
993 } | |
994 | |
2956 | 995 |
996 /* | |
997 * Find existing/active Jabber chat | |
998 */ | |
5572 | 999 static struct jabber_chat *find_existing_chat(GaimConnection *gc, jid chat) |
2956 | 1000 { |
1001 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; | |
1002 struct jabber_chat *jc = NULL; | |
1003 | |
1004 while (jcs) { | |
1005 jc = jcs->data; | |
3311 | 1006 if (jc->state == JCS_ACTIVE && !jid_cmpx(chat, jc->gjid, JID_USER | JID_SERVER)) |
2956 | 1007 break; |
1008 jc = NULL; | |
1009 jcs = jcs->next; | |
1010 } | |
1011 | |
1012 return jc; | |
1013 } | |
1014 | |
1015 /* | |
1016 * Find pending chat | |
1017 */ | |
5572 | 1018 static struct jabber_chat *find_pending_chat(GaimConnection *gc, jid chat) |
2086 | 1019 { |
2956 | 1020 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; |
2086 | 1021 struct jabber_chat *jc = NULL; |
1022 | |
2956 | 1023 while (jcs) { |
1024 jc = jcs->data; | |
3311 | 1025 if (jc->state == JCS_PENDING && !jid_cmpx(chat, jc->gjid, JID_USER | JID_SERVER)) |
2086 | 1026 break; |
1027 jc = NULL; | |
2956 | 1028 jcs = jcs->next; |
2086 | 1029 } |
1030 | |
1031 return jc; | |
1032 } | |
1033 | |
5679 | 1034 static gboolean find_chat_buddy(GaimConversation *b, char *name) |
2086 | 1035 { |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1036 GList *m = gaim_chat_get_users(GAIM_CHAT(b)); |
2086 | 1037 |
1038 while (m) { | |
1039 if (!strcmp(m->data, name)) | |
1040 return TRUE; | |
1041 m = m->next; | |
1042 } | |
1043 | |
1044 return FALSE; | |
1045 } | |
1046 | |
2956 | 1047 /* |
3236 | 1048 * Remove a buddy from the (gaim) buddylist (if he's on it) |
1049 */ | |
5572 | 1050 static void jabber_remove_gaim_buddy(GaimConnection *gc, const char *buddyname) |
3236 | 1051 { |
6695 | 1052 GaimBuddy *b; |
3236 | 1053 |
4687 | 1054 if ((b = gaim_find_buddy(gc->account, buddyname)) != NULL) { |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
1055 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
1056 "removing buddy [1]: %s\n", buddyname); |
4687 | 1057 gaim_blist_remove_buddy(b); |
4349 | 1058 gaim_blist_save(); |
3236 | 1059 } |
1060 } | |
1061 | |
5572 | 1062 static void jabber_change_passwd(GaimConnection *gc, const char *old, const char *new) |
3257 | 1063 { |
1064 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; | |
1065 | |
1066 if(strcmp(old, gjc->pass)) | |
1067 { | |
5436
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
1068 gaim_notify_error(gc, NULL, |
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
1069 _("Unable to change password."), |
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
1070 _("The current password you entered is incorrect. " |
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
1071 "Your password has not been changed.")); |
3257 | 1072 } |
1073 else if(!strcmp(old, new)) | |
1074 { | |
5436
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
1075 gaim_notify_error(gc, NULL, |
6623 | 1076 _("Unable to change password."), |
5436
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
1077 _("The new password you entered is the same as " |
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
1078 "your current password. " |
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
1079 "Your password remains the same.")); |
3257 | 1080 } |
1081 else | |
1082 { | |
1083 xmlnode x, y, z; | |
1084 char *id; | |
1085 | |
1086 x = jutil_iqnew(JPACKET__SET, NS_REGISTER); | |
1087 xmlnode_put_attrib(x, "to", gjc->user->server); | |
1088 y = xmlnode_get_tag(x, "query"); | |
1089 z = xmlnode_insert_tag(y, "username"); | |
1090 xmlnode_insert_cdata(z, gjc->user->user, -1); | |
1091 z = xmlnode_insert_tag(y, "password"); | |
1092 xmlnode_insert_cdata(z, new, -1); | |
1093 | |
1094 id = gjab_getid(gjc); | |
1095 xmlnode_put_attrib(x, "id", id); | |
1096 | |
1097 free(gjc->pass); | |
1098 gjc->pass = strdup(new); | |
1099 | |
1100 g_hash_table_insert(gjc->queries, g_strdup(id), g_strdup("change_password")); | |
1101 | |
1102 gjab_send(gjc, x); | |
1103 xmlnode_free(x); | |
1104 } | |
1105 } | |
3311 | 1106 |
3340 | 1107 /* |
1108 * Return pointer to jabber_buddy_data if buddy found. Create if necessary. | |
1109 */ | |
5572 | 1110 static struct jabber_buddy_data* jabber_find_buddy(GaimConnection *gc, const char *buddy, gboolean create) |
3311 | 1111 { |
6502 | 1112 struct jabber_data *jd; |
3311 | 1113 gpointer val; |
1114 char *realwho; | |
1115 | |
6502 | 1116 if (gc == NULL) |
1117 return NULL; | |
1118 | |
1119 jd = gc->proto_data; | |
3311 | 1120 if((realwho = get_realwho(jd->gjc, buddy, FALSE, NULL)) == NULL) |
1121 return NULL; | |
1122 | |
1123 val = g_hash_table_lookup(jd->buddies, realwho); | |
1124 if(val) { | |
1125 g_free(realwho); | |
1126 return (struct jabber_buddy_data *)val; | |
1127 | |
5135 | 1128 } else if (create) { |
3311 | 1129 struct jabber_buddy_data *jbd = g_new0(struct jabber_buddy_data, 1); |
3340 | 1130 jbd->invisible = JABBER_NOT_INVIS; |
3311 | 1131 g_hash_table_insert(jd->buddies, g_strdup(realwho), jbd); |
1132 g_free(realwho); | |
1133 return jbd; | |
5135 | 1134 } else { |
5940 | 1135 g_free(realwho); |
5135 | 1136 return NULL; |
3311 | 1137 } |
1138 } | |
3770 | 1139 |
3236 | 1140 /* |
3311 | 1141 * find a resource by name, or if no name given, return the "default" resource |
3770 | 1142 * default being the highest priority one. |
3311 | 1143 */ |
1144 | |
5572 | 1145 static jab_res_info jabber_find_resource(GaimConnection *gc, const char *who) |
3311 | 1146 { |
1147 GSList *resources; | |
5135 | 1148 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, who, FALSE); |
3311 | 1149 jab_res_info jri = NULL; |
1150 char *res = strstr(who, "/"); | |
1151 | |
1152 if(res) | |
1153 res++; | |
1154 | |
1155 if(jbd) | |
1156 { | |
1157 resources = jbd->resources; | |
1158 while(resources) | |
1159 { | |
1160 if(!jri && !res) { | |
1161 jri = (jab_res_info) resources->data; | |
1162 } else if(!res) { /* we're looking for the default priority, so... */ | |
1163 if(((jab_res_info) resources->data)->priority >= jri->priority) | |
1164 jri = (jab_res_info) resources->data; | |
3337 | 1165 } else if(((jab_res_info)resources->data)->name) { |
3311 | 1166 if(!strcasecmp(((jab_res_info) resources->data)->name, res)) { |
1167 jri = (jab_res_info) resources->data; | |
1168 break; | |
1169 } | |
1170 } | |
1171 resources = resources->next; | |
1172 } | |
1173 } | |
1174 | |
1175 return jri; | |
1176 } | |
1177 | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
1178 #if 0 |
5572 | 1179 static gboolean jabber_is_default_resource(GaimConnection *gc, const char *who) |
5291 | 1180 { |
1181 jab_res_info jri = jabber_find_resource(gc, who); | |
1182 char *buddy = g_strdup(who); | |
1183 char *resource = strrchr(buddy, '/'); | |
1184 | |
1185 if(!resource || !strcmp(resource+1, jri->name)) { | |
1186 g_free(buddy); | |
1187 return TRUE; | |
1188 } | |
1189 | |
1190 g_free(buddy); | |
1191 return FALSE; | |
1192 } | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
1193 #endif |
5291 | 1194 |
3311 | 1195 /* |
1196 * if the resource doesn't exist, create it. otherwise, just update the priority | |
2956 | 1197 */ |
5572 | 1198 static void jabber_track_resource(GaimConnection *gc, |
3311 | 1199 char *buddy, |
1200 char *res, | |
1201 int priority, | |
1202 int state) | |
1203 { | |
5135 | 1204 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, buddy, TRUE); |
3311 | 1205 |
3337 | 1206 if(jbd) { |
1207 char *who; | |
1208 jab_res_info jri; | |
1209 if(res) | |
1210 who = g_strdup_printf("%s/%s", buddy, res); | |
1211 else | |
1212 who = g_strdup(buddy); | |
1213 jri = jabber_find_resource(gc, who); | |
3311 | 1214 g_free(who); |
1215 if(!jri) { | |
1216 jri = g_new0(struct jabber_resource_info, 1); | |
1217 jri->name = g_strdup(res); | |
1218 jri->away_msg = NULL; | |
5093 | 1219 jri->has_xhtml = TRUE; |
3311 | 1220 jbd->resources = g_slist_append(jbd->resources, jri); |
1221 } | |
1222 jri->priority = priority; | |
1223 jri->state = state; | |
1224 } | |
1225 } | |
1226 | |
1227 /* | |
1228 * remove the resource, if it exists | |
1229 */ | |
5572 | 1230 static void jabber_remove_resource(GaimConnection *gc, char *buddy, char *res) |
2956 | 1231 { |
5135 | 1232 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, buddy, FALSE); |
3337 | 1233 if(jbd) { |
1234 char *who; | |
1235 jab_res_info jri; | |
1236 if(res) | |
1237 who = g_strdup_printf("%s/%s", buddy, res); | |
1238 else | |
1239 who = g_strdup(buddy); | |
1240 jri = jabber_find_resource(gc, who); | |
3311 | 1241 g_free(who); |
1242 if(jri) { | |
3337 | 1243 if(jri->name) |
1244 g_free(jri->name); | |
3311 | 1245 if(jri->away_msg) |
1246 g_free(jri->away_msg); | |
1247 jbd->resources = g_slist_remove(jbd->resources, jri); | |
1248 g_free(jri); | |
1249 } | |
1250 } | |
1251 } | |
1252 | |
1253 /* | |
1254 * grab the away message for the default resource | |
1255 */ | |
1256 static char *jabber_lookup_away(gjconn gjc, char *name) | |
1257 { | |
1258 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), name); | |
1259 | |
4745 | 1260 if(!jri) |
3311 | 1261 return _("Unknown"); |
1262 | |
1263 return jri->away_msg; | |
1264 } | |
4745 | 1265 static const char *jabber_get_state_string(int s) { |
1266 switch(s) { | |
1267 case UC_AWAY: | |
1268 return _("Away"); | |
1269 case UC_CHAT: | |
1270 return _("Chatty"); | |
1271 case UC_XA: | |
1272 return _("Extended Away"); | |
1273 case UC_DND: | |
1274 return _("Do Not Disturb"); | |
1275 default: | |
1276 return _("Available"); | |
1277 } | |
1278 } | |
3311 | 1279 |
1280 static void jabber_track_away(gjconn gjc, jpacket p, char *type) | |
1281 { | |
1282 jab_res_info jri = NULL; | |
1283 | |
3337 | 1284 if(!p || !p->from || !p->from->user) |
3311 | 1285 return; |
1286 | |
1287 jri = jabber_find_resource(GJ_GC(gjc), jid_full(p->from)); | |
1288 | |
1289 if(!jri) | |
1290 return; | |
3770 | 1291 |
3311 | 1292 if(jri->away_msg) |
1293 g_free(jri->away_msg); | |
1294 | |
4745 | 1295 jri->away_msg = g_strdup(xmlnode_get_tag_data(p->x, "status")); |
3311 | 1296 } |
1297 | |
6059 | 1298 static void jabber_convo_closed(GaimConnection *gc, const char *name) |
3311 | 1299 { |
1300 jab_res_info jri = jabber_find_resource(gc, name); | |
1301 | |
1302 if(jri) { | |
1303 if(jri->thread_id) | |
1304 g_free(jri->thread_id); | |
1305 | |
1306 jri->thread_id = NULL; | |
2956 | 1307 } |
1308 } | |
1309 | |
3311 | 1310 static void jabber_track_convo_thread(gjconn gjc, char *name, char *thread_id) |
1311 { | |
1312 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), name); | |
1313 | |
1314 if(jri) { | |
1315 if(jri->thread_id) | |
1316 g_free(jri->thread_id); | |
1317 | |
1318 jri->thread_id = g_strdup(thread_id); | |
1319 } | |
1320 } | |
1321 | |
5136 | 1322 static char *jabber_get_convo_thread(gjconn gjc, const char *name) |
3311 | 1323 { |
1324 char *ct = NULL; | |
1325 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), name); | |
1326 | |
1327 if(jri) { | |
1328 if(jri->thread_id) | |
1329 ct = g_strdup(jri->thread_id); | |
1330 } | |
5135 | 1331 |
3311 | 1332 return ct; |
1333 } | |
1334 | |
1335 | |
5426 | 1336 static time_t str_to_time(char *timestamp) |
3159 | 1337 { |
5426 | 1338 struct tm t; |
1339 time_t retval = 0; | |
1340 char buf[32]; | |
1341 char *c; | |
1342 int tzoff = 0; | |
1343 | |
1344 time(&retval); | |
1345 localtime_r(&retval, &t); | |
1346 | |
1347 snprintf(buf, sizeof(buf), "%s", timestamp); | |
1348 c = buf; | |
1349 | |
1350 /* 4 digit year */ | |
1351 if(!sscanf(c, "%04d", &t.tm_year)) return 0; | |
1352 c+=4; | |
1353 if(*c == '-') | |
1354 c++; | |
1355 | |
1356 t.tm_year -= 1900; | |
1357 | |
1358 /* 2 digit month */ | |
1359 if(!sscanf(c, "%02d", &t.tm_mon)) return 0; | |
1360 c+=2; | |
1361 if(*c == '-') | |
1362 c++; | |
1363 | |
1364 t.tm_mon -= 1; | |
1365 | |
1366 /* 2 digit day */ | |
1367 if(!sscanf(c, "%02d", &t.tm_mday)) return 0; | |
1368 c+=2; | |
1369 | |
1370 if(*c == 'T') { /* we have more than a date, keep going */ | |
1371 c++; /* skip the "T" */ | |
1372 | |
1373 /* 2 digit hour */ | |
1374 if(sscanf(c, "%02d:%02d:%02d", &t.tm_hour, &t.tm_min, &t.tm_sec)) { | |
1375 int tzhrs, tzmins; | |
1376 c+=8; | |
1377 if(*c == '.') /* dealing with precision we don't care about */ | |
1378 c += 4; | |
1379 | |
1380 if((*c == '+' || *c == '-') && | |
1381 sscanf(c+1, "%02d:%02d", &tzhrs, &tzmins)) { | |
1382 tzoff = tzhrs*60*60 + tzmins*60; | |
1383 if(*c == '+') | |
1384 tzoff *= -1; | |
5279 | 1385 } |
5426 | 1386 |
1387 #ifdef HAVE_TM_GMTOFF | |
1388 tzoff += t.tm_gmtoff; | |
1389 #else | |
1390 # ifdef HAVE_TIMEZONE | |
1391 tzset(); /* making sure */ | |
1392 tzoff -= timezone; | |
1393 # endif | |
1394 #endif | |
5279 | 1395 } |
3229 | 1396 } |
5426 | 1397 retval = mktime(&t); |
1398 | |
1399 retval += tzoff; | |
1400 | |
1401 return retval; | |
3159 | 1402 } |
1403 | |
2956 | 1404 static void jabber_handlemessage(gjconn gjc, jpacket p) |
2086 | 1405 { |
3311 | 1406 xmlnode y, subj; |
3159 | 1407 time_t time_sent = time(NULL); |
3311 | 1408 gboolean typing = FALSE; |
5093 | 1409 gboolean has_xhtml = TRUE; |
2086 | 1410 |
1411 char *from = NULL, *msg = NULL, *type = NULL, *topic = NULL; | |
3311 | 1412 char *thread_id = NULL; |
1413 char *conference_room = NULL; | |
2086 | 1414 char m[BUF_LONG * 2]; |
1415 | |
1416 type = xmlnode_get_attrib(p->x, "type"); | |
3769 | 1417 |
3311 | 1418 if ((y = xmlnode_get_tag(p->x, "thread"))) |
1419 thread_id = xmlnode_get_data(y); | |
1420 | |
1421 y = xmlnode_get_firstchild(p->x); | |
1422 | |
1423 while(y) { | |
1424 if(NSCHECK(y, NS_DELAY)) { | |
1425 char *timestamp = xmlnode_get_attrib(y, "stamp"); | |
5426 | 1426 if(timestamp) |
1427 time_sent = str_to_time(timestamp); | |
3311 | 1428 } else if(NSCHECK(y, "jabber:x:event")) { |
1429 if(xmlnode_get_tag(y, "composing")) | |
1430 typing = TRUE; | |
1431 } else if(NSCHECK(y, "jabber:x:conference")) { | |
1432 conference_room = xmlnode_get_attrib(y, "jid"); | |
1433 } | |
1434 y = xmlnode_get_nextsibling(y); | |
3159 | 1435 } |
1436 | |
2086 | 1437 if (!type || !strcasecmp(type, "normal") || !strcasecmp(type, "chat")) { |
1438 | |
1439 from = jid_full(p->from); | |
6953 | 1440 /* a gross hack because i'm a nice guy */ |
1441 if ((y = xmlnode_get_tag(p->x, "html")) && xmlnode_get_tag(y, "body")) { | |
5093 | 1442 msg = xmlnode2str(y); |
1443 } else if ((y = xmlnode_get_tag(p->x, "body"))) { | |
2086 | 1444 msg = xmlnode_get_data(y); |
5093 | 1445 has_xhtml = FALSE; |
2086 | 1446 } |
1447 | |
1448 if (!from) | |
1449 return; | |
1450 | |
3311 | 1451 if (conference_room) { |
5234 | 1452 GHashTable *components = g_hash_table_new_full(g_str_hash, |
1453 g_str_equal, g_free, g_free); | |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
1454 char **data; |
2086 | 1455 |
3311 | 1456 data = g_strsplit(conference_room, "@", 2); |
5234 | 1457 g_hash_table_replace(components, g_strdup("room"), |
1458 g_strdup(data[0])); | |
1459 g_hash_table_replace(components, g_strdup("server"), | |
1460 g_strdup(data[1])); | |
1461 g_hash_table_replace(components, g_strdup("handle"), | |
1462 g_strdup(gjc->user->user)); | |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
1463 g_strfreev(data); |
2086 | 1464 |
5234 | 1465 serv_got_chat_invite(GJ_GC(gjc), conference_room, from, msg, components); |
2086 | 1466 } else if (msg) { /* whisper */ |
1467 struct jabber_chat *jc; | |
1468 g_snprintf(m, sizeof(m), "%s", msg); | |
2956 | 1469 if (((jc = find_existing_chat(GJ_GC(gjc), p->from)) != NULL) && jc->b) |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1470 serv_got_chat_in(GJ_GC(gjc), |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1471 gaim_chat_get_id(GAIM_CHAT(jc->b)), |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1472 p->from->resource, 1, m, time_sent); |
2086 | 1473 else { |
2278
00a8b7bcef6c
[gaim-migrate @ 2288]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2232
diff
changeset
|
1474 int flags = 0; |
3769 | 1475 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), from); |
5093 | 1476 if(jri) { |
1477 if(typing) | |
1478 jri->has_composing = TRUE; | |
1479 jri->has_xhtml = has_xhtml; | |
1480 } | |
3769 | 1481 jabber_track_convo_thread(gjc, from, thread_id); |
6640
314111e7b601
[gaim-migrate @ 7165]
Christian Hammond <chipx86@chipx86.com>
parents:
6638
diff
changeset
|
1482 if (gaim_find_conversation_with_account(from, GJ_GC(gjc)->account)) |
3769 | 1483 serv_got_im(GJ_GC(gjc), from, m, flags, |
3311 | 1484 time_sent, -1); |
2086 | 1485 else { |
2956 | 1486 if(p->from->user) { |
3311 | 1487 from = g_strdup_printf("%s@%s", p->from->user, |
1488 p->from->server); | |
2956 | 1489 } else { |
3311 | 1490 /* server message? */ |
1491 from = g_strdup(p->from->server); | |
2956 | 1492 } |
3159 | 1493 serv_got_im(GJ_GC(gjc), from, m, flags, time_sent, -1); |
2086 | 1494 g_free(from); |
1495 } | |
1496 } | |
3311 | 1497 } else { |
1498 /* a non-message message! */ | |
1499 from = g_strdup_printf("%s@%s", p->from->user, p->from->server); | |
1500 if(typing) | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
1501 serv_got_typing(GJ_GC(gjc), from, 0, GAIM_TYPING); |
3311 | 1502 else |
1503 serv_got_typing_stopped(GJ_GC(gjc), from); | |
1504 g_free(from); | |
2086 | 1505 } |
1506 | |
1507 } else if (!strcasecmp(type, "error")) { | |
1508 if ((y = xmlnode_get_tag(p->x, "error"))) { | |
1509 type = xmlnode_get_attrib(y, "code"); | |
1510 msg = xmlnode_get_data(y); | |
1511 } | |
1512 | |
1513 if (msg) { | |
3427 | 1514 from = g_strdup_printf(_("Jabber Error %s"), type ? type : ""); |
5436
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
1515 gaim_notify_error(GJ_GC(gjc), NULL, from, msg); |
2086 | 1516 g_free(from); |
1517 } | |
1518 } else if (!strcasecmp(type, "groupchat")) { | |
1519 struct jabber_chat *jc; | |
1520 static int i = 0; | |
1521 | |
6953 | 1522 /* a gross hack because i'm a nice guy */ |
1523 if ((y = xmlnode_get_tag(p->x, "html")) && xmlnode_get_tag(y, "body")) { | |
5093 | 1524 msg = xmlnode2str(y); |
1525 } else if ((y = xmlnode_get_tag(p->x, "body"))) { | |
2086 | 1526 msg = xmlnode_get_data(y); |
1527 } | |
1528 | |
1529 if ((subj = xmlnode_get_tag(p->x, "subject"))) { | |
3770 | 1530 topic = xmlnode_get_data(subj); |
1531 } | |
2086 | 1532 |
2956 | 1533 jc = find_existing_chat(GJ_GC(gjc), p->from); |
2086 | 1534 if (!jc) { |
1535 /* we're not in this chat. are we supposed to be? */ | |
2956 | 1536 if ((jc = find_pending_chat(GJ_GC(gjc), p->from)) != NULL) { |
2086 | 1537 /* yes, we're supposed to be. so now we are. */ |
2956 | 1538 jc->b = serv_got_joined_chat(GJ_GC(gjc), i++, p->from->user); |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1539 jc->id = gaim_chat_get_id(GAIM_CHAT(jc->b)); |
2956 | 1540 jc->state = JCS_ACTIVE; |
2086 | 1541 } else { |
1542 /* no, we're not supposed to be. */ | |
1543 return; | |
1544 } | |
1545 } | |
1546 if (p->from->resource) { | |
1547 if (!y) { | |
2956 | 1548 if (!find_chat_buddy(jc->b, p->from->resource)) { |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1549 gaim_chat_add_user(GAIM_CHAT(jc->b), |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1550 p->from->resource, NULL); |
2956 | 1551 } else if ((y = xmlnode_get_tag(p->x, "status"))) { |
3311 | 1552 jabber_track_away(gjc, p, NULL); |
2086 | 1553 } |
1554 } else if (jc->b && msg) { | |
1555 char buf[8192]; | |
1556 | |
1557 if (topic) { | |
1558 char tbuf[8192]; | |
1559 g_snprintf(tbuf, sizeof(tbuf), "%s", topic); | |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1560 gaim_chat_set_topic(GAIM_CHAT(jc->b), |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1561 p->from->resource, tbuf); |
2086 | 1562 } |
1563 | |
1564 g_snprintf(buf, sizeof(buf), "%s", msg); | |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1565 serv_got_chat_in(GJ_GC(gjc), |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1566 gaim_chat_get_id(GAIM_CHAT(jc->b)), |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1567 p->from->resource, 0, buf, time_sent); |
2086 | 1568 } |
1569 } else { /* message from the server */ | |
3770 | 1570 if(jc->b && topic) { |
1571 char tbuf[8192]; | |
2086 | 1572 g_snprintf(tbuf, sizeof(tbuf), "%s", topic); |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1573 gaim_chat_set_topic(GAIM_CHAT(jc->b), "", tbuf); |
2086 | 1574 } |
1575 } | |
1576 | |
1577 } else { | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
1578 gaim_debug(GAIM_DEBUG_WARNING, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
1579 "unhandled message %s\n", type); |
2086 | 1580 } |
1581 } | |
3770 | 1582 |
2956 | 1583 static void jabber_handlepresence(gjconn gjc, jpacket p) |
2086 | 1584 { |
6817 | 1585 char *from, *type; |
6695 | 1586 GaimBuddy *b = NULL; |
3311 | 1587 gaim_jid gjid; |
2086 | 1588 char *buddy; |
3194 | 1589 xmlnode y; |
2086 | 1590 char *show; |
2501
227cc42ffa6e
[gaim-migrate @ 2514]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2382
diff
changeset
|
1591 int state = 0; |
5679 | 1592 GaimConversation *cnv = NULL; |
2086 | 1593 struct jabber_chat *jc = NULL; |
3311 | 1594 int priority = 0; |
1595 struct jabber_buddy_data *jbd; | |
3770 | 1596 |
2086 | 1597 from = xmlnode_get_attrib(p->x, "from"); |
1598 type = xmlnode_get_attrib(p->x, "type"); | |
3770 | 1599 |
3311 | 1600 if((buddy = get_realwho(gjc, from, FALSE, &gjid)) == NULL) |
1601 return; | |
1602 | |
1603 if (gjid->user == NULL) { | |
1604 /* FIXME: transport */ | |
1605 g_free(buddy); | |
1606 gaim_jid_free(gjid); | |
1607 return; | |
1608 } | |
1609 | |
5135 | 1610 jbd = jabber_find_buddy(GJ_GC(gjc), buddy, TRUE); |
3311 | 1611 |
1612 if(jbd->error_msg) { | |
1613 g_free(jbd->error_msg); | |
1614 jbd->error_msg = NULL; | |
1615 } | |
1616 | |
3259 | 1617 if(type && !strcasecmp(type, "error")) { |
1618 state = UC_ERROR; | |
3311 | 1619 if((y = xmlnode_get_tag(p->x, "error")) != NULL) { |
1620 jbd->error_msg = g_strdup_printf(_("Error %s: %s"), | |
1621 xmlnode_get_attrib(y, "code"), xmlnode_get_data(y)); | |
1622 } else { | |
1623 jbd->error_msg = g_strdup(_("Unknown Error in presence")); | |
1624 } | |
3259 | 1625 } else { |
1626 if ((y = xmlnode_get_tag(p->x, "show"))) { | |
1627 show = xmlnode_get_data(y); | |
1628 if (!show) { | |
1629 state = 0; | |
1630 } else if (!strcasecmp(show, "away")) { | |
1631 state = UC_AWAY; | |
1632 } else if (!strcasecmp(show, "chat")) { | |
1633 state = UC_CHAT; | |
1634 } else if (!strcasecmp(show, "xa")) { | |
1635 state = UC_XA; | |
1636 } else if (!strcasecmp(show, "dnd")) { | |
1637 state = UC_DND; | |
1638 } | |
1639 } else { | |
2501
227cc42ffa6e
[gaim-migrate @ 2514]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2382
diff
changeset
|
1640 state = 0; |
2086 | 1641 } |
1642 } | |
1643 | |
5291 | 1644 if ((y = xmlnode_get_tag(p->x, "priority"))) |
1645 priority = atoi(xmlnode_get_data(y)); | |
1646 | |
2086 | 1647 /* um. we're going to check if it's a chat. if it isn't, and there are pending |
2956 | 1648 * chats, create the chat. if there aren't pending chats and we don't have the |
1649 * buddy on our list, simply bail out. */ | |
3311 | 1650 if ((cnv = find_chat(GJ_GC(gjc), gjid->user)) == NULL) { |
2086 | 1651 static int i = 0x70; |
3311 | 1652 if ((jc = find_pending_chat(GJ_GC(gjc), gjid)) != NULL) { |
1653 jc->b = cnv = serv_got_joined_chat(GJ_GC(gjc), i++, gjid->user); | |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1654 jc->id = gaim_chat_get_id(GAIM_CHAT(jc->b)); |
2956 | 1655 jc->state = JCS_ACTIVE; |
4687 | 1656 } else if ((b = gaim_find_buddy(GJ_GC(gjc)->account, buddy)) == NULL) { |
2956 | 1657 g_free(buddy); |
3311 | 1658 gaim_jid_free(gjid); |
2956 | 1659 return; |
2086 | 1660 } |
1661 } | |
1662 | |
4732 | 1663 if (state == UC_ERROR || (type && (strcasecmp(type, "unavailable") == 0))) |
3311 | 1664 jabber_remove_resource(GJ_GC(gjc), buddy, gjid->resource); |
1665 else { | |
1666 jabber_track_resource(GJ_GC(gjc), buddy, gjid->resource, priority, state); | |
1667 | |
1668 /* keep track of away msg somewhat the same as the yahoo plugin */ | |
1669 jabber_track_away(gjc, p, type); | |
1670 } | |
3770 | 1671 |
2086 | 1672 if (!cnv) { |
3311 | 1673 /* this is where we handle presence information for "regular" buddies */ |
1674 jab_res_info jri = jabber_find_resource(GJ_GC(gjc), buddy); | |
1675 if(jri) { | |
4732 | 1676 serv_got_update(GJ_GC(gjc), buddy, 1, 0, b->signon, b->idle, jri->state); |
3311 | 1677 } else |
4732 | 1678 serv_got_update(GJ_GC(gjc), buddy, 0, 0, 0, 0, 0); |
3311 | 1679 |
2086 | 1680 } else { |
3311 | 1681 if (gjid->resource) { |
3259 | 1682 if (type && (!strcasecmp(type, "unavailable"))) { |
2086 | 1683 struct jabber_data *jd; |
3311 | 1684 if (!jc && !(jc = find_existing_chat(GJ_GC(gjc), gjid))) { |
2086 | 1685 g_free(buddy); |
3311 | 1686 gaim_jid_free(gjid); |
2086 | 1687 return; |
1688 } | |
1689 jd = jc->gc->proto_data; | |
2956 | 1690 /* if it's not ourselves...*/ |
3311 | 1691 if (strcmp(gjid->resource, jc->gjid->resource) && jc->b) { |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1692 gaim_chat_remove_user(GAIM_CHAT(jc->b), gjid->resource, |
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1693 NULL); |
2086 | 1694 g_free(buddy); |
3311 | 1695 gaim_jid_free(gjid); |
2086 | 1696 return; |
1697 } | |
2956 | 1698 |
1699 jc->state = JCS_CLOSED; | |
1700 serv_got_chat_left(GJ_GC(gjc), jc->id); | |
1701 /* | |
1702 * TBD: put back some day? | |
1703 jd->chats = g_slist_remove(jd->chats, jc); | |
1704 g_free(jc); | |
1705 */ | |
1706 } else { | |
3311 | 1707 if ((!jc && !(jc = find_existing_chat(GJ_GC(gjc), gjid))) || !jc->b) { |
2956 | 1708 g_free(buddy); |
3311 | 1709 gaim_jid_free(gjid); |
2956 | 1710 return; |
1711 } | |
3311 | 1712 if (!find_chat_buddy(jc->b, gjid->resource)) { |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4357
diff
changeset
|
1713 gaim_chat_add_user(GAIM_CHAT(jc->b), gjid->resource, NULL); |
2086 | 1714 } |
1715 } | |
1716 } | |
1717 } | |
1718 | |
1719 g_free(buddy); | |
3311 | 1720 gaim_jid_free(gjid); |
2086 | 1721 |
1722 return; | |
1723 } | |
1724 | |
3229 | 1725 /* |
1726 * Used only by Jabber accept/deny add stuff just below | |
1727 */ | |
1728 struct jabber_add_permit { | |
5572 | 1729 GaimConnection *gc; |
3229 | 1730 gchar *user; |
1731 }; | |
1732 | |
1733 /* | |
1734 * Common part for Jabber accept/deny adds | |
1735 * | |
1736 * "type" says whether we'll permit/deny the subscribe request | |
1737 */ | |
1738 static void jabber_accept_deny_add(struct jabber_add_permit *jap, const char *type) | |
1739 { | |
1740 xmlnode g = xmlnode_new_tag("presence"); | |
1741 | |
1742 xmlnode_put_attrib(g, "to", jap->user); | |
1743 xmlnode_put_attrib(g, "type", type); | |
4249 | 1744 gjab_send(GC_GJ(jap->gc), g); |
3229 | 1745 |
1746 xmlnode_free(g); | |
1747 } | |
1748 | |
1749 /* | |
5498
cce2d7868c78
[gaim-migrate @ 5894]
Christian Hammond <chipx86@chipx86.com>
parents:
5436
diff
changeset
|
1750 * Callback from "accept" in gaim_request_action() invoked |
cce2d7868c78
[gaim-migrate @ 5894]
Christian Hammond <chipx86@chipx86.com>
parents:
5436
diff
changeset
|
1751 * by jabber_handles10n() |
3229 | 1752 */ |
3730 | 1753 static void jabber_accept_add(struct jabber_add_permit *jap) |
3229 | 1754 { |
5578
847ad796326d
[gaim-migrate @ 5982]
Christian Hammond <chipx86@chipx86.com>
parents:
5572
diff
changeset
|
1755 if(g_list_find(gaim_connections_get_all(), jap->gc)) { |
4249 | 1756 jabber_accept_deny_add(jap, "subscribed"); |
1757 /* | |
1758 * If we don't already have the buddy on *our* buddylist, | |
1759 * ask if we want him or her added. | |
1760 */ | |
4687 | 1761 if(gaim_find_buddy(jap->gc->account, jap->user) == NULL) { |
4249 | 1762 show_got_added(jap->gc, NULL, jap->user, NULL, NULL); |
1763 } | |
3229 | 1764 } |
4249 | 1765 |
3229 | 1766 g_free(jap->user); |
1767 g_free(jap); | |
1768 } | |
1769 | |
1770 /* | |
5498
cce2d7868c78
[gaim-migrate @ 5894]
Christian Hammond <chipx86@chipx86.com>
parents:
5436
diff
changeset
|
1771 * Callback from "deny/cancel" in gaim_request_action() invoked |
cce2d7868c78
[gaim-migrate @ 5894]
Christian Hammond <chipx86@chipx86.com>
parents:
5436
diff
changeset
|
1772 * by jabber_handles10n() |
3229 | 1773 */ |
3730 | 1774 static void jabber_deny_add(struct jabber_add_permit *jap) |
3229 | 1775 { |
5578
847ad796326d
[gaim-migrate @ 5982]
Christian Hammond <chipx86@chipx86.com>
parents:
5572
diff
changeset
|
1776 if(g_list_find(gaim_connections_get_all(), jap->gc)) { |
4249 | 1777 jabber_accept_deny_add(jap, "unsubscribed"); |
1778 } | |
1779 | |
3229 | 1780 g_free(jap->user); |
1781 g_free(jap); | |
1782 } | |
1783 | |
1784 /* | |
1785 * Handle subscription requests | |
1786 */ | |
2956 | 1787 static void jabber_handles10n(gjconn gjc, jpacket p) |
2086 | 1788 { |
1789 xmlnode g; | |
1790 char *Jid = xmlnode_get_attrib(p->x, "from"); | |
3136 | 1791 char *type = xmlnode_get_attrib(p->x, "type"); |
2086 | 1792 |
1793 g = xmlnode_new_tag("presence"); | |
1794 xmlnode_put_attrib(g, "to", Jid); | |
3229 | 1795 |
1796 if (!strcmp(type, "subscribe")) { | |
1797 /* | |
1798 * A "subscribe to us" request was received - put up the approval dialog | |
1799 */ | |
1800 struct jabber_add_permit *jap = g_new0(struct jabber_add_permit, 1); | |
1801 gchar *msg = g_strdup_printf(_("The user %s wants to add you to their buddy list."), | |
1802 Jid); | |
1803 | |
4249 | 1804 jap->gc = GJ_GC(gjc); |
3229 | 1805 jap->user = g_strdup(Jid); |
5498
cce2d7868c78
[gaim-migrate @ 5894]
Christian Hammond <chipx86@chipx86.com>
parents:
5436
diff
changeset
|
1806 |
cce2d7868c78
[gaim-migrate @ 5894]
Christian Hammond <chipx86@chipx86.com>
parents:
5436
diff
changeset
|
1807 gaim_request_action(jap->gc, NULL, msg, NULL, 0, jap, 2, |
cce2d7868c78
[gaim-migrate @ 5894]
Christian Hammond <chipx86@chipx86.com>
parents:
5436
diff
changeset
|
1808 _("Authorize"), G_CALLBACK(jabber_accept_add), |
cce2d7868c78
[gaim-migrate @ 5894]
Christian Hammond <chipx86@chipx86.com>
parents:
5436
diff
changeset
|
1809 _("Deny"), G_CALLBACK(jabber_deny_add)); |
3229 | 1810 |
1811 g_free(msg); | |
1812 xmlnode_free(g); /* Never needed it here anyway */ | |
1813 return; | |
1814 | |
1815 } else if (!strcmp(type, "unsubscribe")) { | |
1816 /* | |
1817 * An "unsubscribe to us" was received - simply "approve" it | |
1818 */ | |
2086 | 1819 xmlnode_put_attrib(g, "type", "unsubscribed"); |
3229 | 1820 } else { |
1821 /* | |
1822 * Did we attempt to subscribe to somebody and they do not exist? | |
1823 */ | |
3136 | 1824 if (!strcmp(type, "unsubscribed")) { |
1825 xmlnode y; | |
1826 char *status; | |
1827 if((y = xmlnode_get_tag(p->x, "status")) && (status = xmlnode_get_data(y)) && | |
1828 !strcmp(status, "Not Found")) { | |
3427 | 1829 char *msg = g_strdup_printf(_("The Jabber user %s does not exist and was therefore " |
1830 "not added to your roster."), | |
1831 xmlnode_get_attrib(p->x, "from")); | |
5436
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
1832 gaim_notify_error(GJ_GC(gjc), NULL, _("No such user."), msg); |
3136 | 1833 g_free(msg); |
1834 } | |
1835 } | |
1836 | |
2956 | 1837 xmlnode_free(g); |
2086 | 1838 return; |
2956 | 1839 } |
1840 | |
1841 gjab_send(gjc, g); | |
1842 xmlnode_free(g); | |
2086 | 1843 } |
1844 | |
2956 | 1845 /* |
1846 * Pending subscription to a buddy? | |
1847 */ | |
1848 #define BUD_SUB_TO_PEND(sub, ask) ((!strcasecmp((sub), "none") || !strcasecmp((sub), "from")) && \ | |
3770 | 1849 (ask) != NULL && !strcasecmp((ask), "subscribe")) |
2956 | 1850 |
1851 /* | |
1852 * Subscribed to a buddy? | |
1853 */ | |
1854 #define BUD_SUBD_TO(sub, ask) ((!strcasecmp((sub), "to") || !strcasecmp((sub), "both")) && \ | |
1855 ((ask) == NULL || !strcasecmp((ask), "subscribe"))) | |
1856 | |
1857 /* | |
1858 * Pending unsubscription to a buddy? | |
1859 */ | |
1860 #define BUD_USUB_TO_PEND(sub, ask) ((!strcasecmp((sub), "to") || !strcasecmp((sub), "both")) && \ | |
1861 (ask) != NULL && !strcasecmp((ask), "unsubscribe")) | |
1862 | |
1863 /* | |
1864 * Unsubscribed to a buddy? | |
1865 */ | |
1866 #define BUD_USUBD_TO(sub, ask) ((!strcasecmp((sub), "none") || !strcasecmp((sub), "from")) && \ | |
1867 ((ask) == NULL || !strcasecmp((ask), "unsubscribe"))) | |
1868 | |
1869 /* | |
1870 * If a buddy is added or removed from the roster on another resource | |
1871 * jabber_handlebuddy is called | |
1872 * | |
1873 * Called with roster item node. | |
1874 */ | |
1875 static void jabber_handlebuddy(gjconn gjc, xmlnode x) | |
1876 { | |
1877 xmlnode g; | |
3311 | 1878 char *who, *name, *sub, *ask; |
1879 gaim_jid gjid; | |
6695 | 1880 GaimBuddy *b = NULL; |
4927 | 1881 struct jabber_buddy_data *jbd = NULL; |
3136 | 1882 char *buddyname, *groupname = NULL; |
2956 | 1883 |
3311 | 1884 who = xmlnode_get_attrib(x, "jid"); |
2956 | 1885 name = xmlnode_get_attrib(x, "name"); |
1886 sub = xmlnode_get_attrib(x, "subscription"); | |
1887 ask = xmlnode_get_attrib(x, "ask"); | |
3311 | 1888 |
1889 if((buddyname = get_realwho(gjc, who, FALSE, &gjid)) == NULL) | |
1890 return; | |
2956 | 1891 |
4705 | 1892 |
2956 | 1893 /* JFIXME: jabber_handleroster() had a "FIXME: transport" at this |
1894 * equivilent point. So... | |
1895 * | |
3311 | 1896 * We haven't done anything interesting to this point, so we'll |
1897 * violate Good Coding Structure here by simply bailing out. | |
2956 | 1898 */ |
3311 | 1899 if(!gjid->user) { |
1900 g_free(buddyname); | |
1901 gaim_jid_free(gjid); | |
2956 | 1902 return; |
1903 } | |
3311 | 1904 gaim_jid_free(gjid); |
2956 | 1905 |
3236 | 1906 if((g = xmlnode_get_tag(x, "group")) != NULL) { |
3136 | 1907 groupname = xmlnode_get_data(g); |
2956 | 1908 } |
1909 | |
3059 | 1910 /* |
3136 | 1911 * Add or remove a buddy? Change buddy's alias or group? |
3059 | 1912 */ |
2956 | 1913 if (BUD_SUB_TO_PEND(sub, ask) || BUD_SUBD_TO(sub, ask)) { |
4687 | 1914 if ((b = gaim_find_buddy(GJ_GC(gjc)->account, buddyname)) == NULL) { |
6695 | 1915 GaimGroup *g; |
4927 | 1916 b = gaim_buddy_new(GJ_GC(gjc)->account, buddyname, name); |
6808 | 1917 |
1918 if(!groupname) | |
1919 groupname = _("Buddies"); | |
1920 | |
1921 if (!(g = gaim_find_group(groupname))) { | |
1922 g = gaim_group_new(groupname); | |
4775 | 1923 gaim_blist_add_group(g, NULL); |
1924 } | |
6808 | 1925 |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
1926 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
1927 "adding buddy [4]: %s\n", buddyname); |
6695 | 1928 gaim_blist_add_buddy(b, NULL, g, NULL); |
4349 | 1929 gaim_blist_save(); |
3136 | 1930 } else { |
5264 | 1931 gboolean save = FALSE; |
6695 | 1932 GaimGroup *c_grp = gaim_find_buddys_group(b); |
3136 | 1933 |
3770 | 1934 /* |
3136 | 1935 * If the buddy's in a new group or his/her alias is changed... |
1936 */ | |
1937 if(groupname && c_grp && strcmp(c_grp->name, groupname)) { | |
6695 | 1938 GaimGroup *g = gaim_find_group(groupname); |
5264 | 1939 if(!g) { |
1940 g = gaim_group_new(groupname); | |
1941 gaim_blist_add_group(g, NULL); | |
1942 } | |
1943 | |
6695 | 1944 gaim_blist_add_buddy(b, NULL, g, NULL); |
5264 | 1945 save = TRUE; |
1946 } | |
1947 | |
1948 if(name && (!b->alias || strcmp(b->alias, name))) { | |
1949 gaim_blist_alias_buddy(b, name); | |
1950 save = TRUE; | |
1951 } | |
1952 | |
1953 if(save) | |
4349 | 1954 gaim_blist_save(); |
2956 | 1955 } |
1956 } else if (BUD_USUB_TO_PEND(sub, ask) || BUD_USUBD_TO(sub, ask) || !strcasecmp(sub, "remove")) { | |
3236 | 1957 jabber_remove_gaim_buddy(GJ_GC(gjc), buddyname); |
2956 | 1958 } |
5135 | 1959 if(b && (jbd = jabber_find_buddy(b->account->gc, buddyname, TRUE)) != NULL) { |
4927 | 1960 jbd->subscription = JABBER_SUB_NONE; |
1961 if(!strcasecmp(sub, "to")) | |
1962 jbd->subscription |= JABBER_SUB_TO; | |
1963 else if(!strcasecmp(sub, "from")) | |
1964 jbd->subscription |= JABBER_SUB_FROM; | |
1965 else if(!strcasecmp(sub, "both")) | |
1966 jbd->subscription |= JABBER_SUB_BOTH; | |
1967 | |
1968 if(ask && !strcasecmp(ask, "subscribe")) | |
1969 jbd->subscription |= JABBER_SUB_PENDING; | |
1970 } | |
3328 | 1971 |
2956 | 1972 g_free(buddyname); |
1973 | |
1974 } | |
1975 | |
1976 static void jabber_handleroster(gjconn gjc, xmlnode querynode) | |
2086 | 1977 { |
1978 xmlnode x; | |
1979 | |
1980 x = xmlnode_get_firstchild(querynode); | |
1981 while (x) { | |
2956 | 1982 jabber_handlebuddy(gjc, x); |
2086 | 1983 x = xmlnode_get_nextsibling(x); |
1984 } | |
1985 | |
5426 | 1986 x = xmlnode_new_tag("presence"); |
2956 | 1987 gjab_send(gjc, x); |
2086 | 1988 xmlnode_free(x); |
1989 } | |
1990 | |
2956 | 1991 static void jabber_handleauthresp(gjconn gjc, jpacket p) |
2086 | 1992 { |
1993 if (jpacket_subtype(p) == JPACKET__RESULT) { | |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
1994 if (xmlnode_has_children(p->x)) { |
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
1995 xmlnode query = xmlnode_get_tag(p->x, "query"); |
5572 | 1996 gaim_connection_update_progress(GJ_GC(gjc), _("Authenticating"), |
1997 4, JABBER_CONNECT_STEPS); | |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
1998 if (!xmlnode_get_tag(query, "digest")) { |
2956 | 1999 g_free(gjc->sid); |
2000 gjc->sid = NULL; | |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
2001 } |
2956 | 2002 gjab_auth(gjc); |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
2003 } else { |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2004 gaim_debug(GAIM_DEBUG_INFO, "jabber", "auth success\n"); |
2086 | 2005 |
5572 | 2006 gaim_connection_set_state(GJ_GC(gjc), GAIM_CONNECTED); |
2956 | 2007 serv_finish_login(GJ_GC(gjc)); |
2008 | |
2009 ((struct jabber_data *)GJ_GC(gjc)->proto_data)->did_import = TRUE; | |
2010 | |
2011 gjab_reqroster(gjc); | |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
2012 } |
2086 | 2013 } else { |
2014 xmlnode xerr; | |
2015 char *errmsg = NULL; | |
2016 int errcode = 0; | |
2017 | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2018 gaim_debug(GAIM_DEBUG_ERROR, "jabber", "auth failed\n"); |
2086 | 2019 xerr = xmlnode_get_tag(p->x, "error"); |
2020 if (xerr) { | |
2021 char msg[BUF_LONG]; | |
2022 errmsg = xmlnode_get_data(xerr); | |
2023 if (xmlnode_get_attrib(xerr, "code")) { | |
2024 errcode = atoi(xmlnode_get_attrib(xerr, "code")); | |
2025 g_snprintf(msg, sizeof(msg), "Error %d: %s", errcode, errmsg); | |
2026 } else | |
2027 g_snprintf(msg, sizeof(msg), "%s", errmsg); | |
5572 | 2028 gaim_connection_error(GJ_GC(gjc), msg); |
2086 | 2029 } else { |
5572 | 2030 gaim_connection_error(GJ_GC(gjc), _("Unknown login error")); |
2086 | 2031 } |
2032 } | |
2033 } | |
2034 | |
2956 | 2035 static void jabber_handleversion(gjconn gjc, xmlnode iqnode) { |
2086 | 2036 xmlnode querynode, x; |
2037 char *id, *from; | |
2038 char os[1024]; | |
2039 struct utsname osinfo; | |
2040 | |
2041 uname(&osinfo); | |
2042 g_snprintf(os, sizeof os, "%s %s %s", osinfo.sysname, osinfo.release, osinfo.machine); | |
2043 | |
2044 id = xmlnode_get_attrib(iqnode, "id"); | |
2045 from = xmlnode_get_attrib(iqnode, "from"); | |
2046 | |
2047 x = jutil_iqnew(JPACKET__RESULT, NS_VERSION); | |
2048 | |
2049 xmlnode_put_attrib(x, "to", from); | |
2050 xmlnode_put_attrib(x, "id", id); | |
2051 querynode = xmlnode_get_tag(x, "query"); | |
2052 xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "name"), PACKAGE, -1); | |
2053 xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "version"), VERSION, -1); | |
2054 xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "os"), os, -1); | |
2055 | |
2956 | 2056 gjab_send(gjc, x); |
2086 | 2057 |
2058 xmlnode_free(x); | |
2059 } | |
2060 | |
2956 | 2061 static void jabber_handletime(gjconn gjc, xmlnode iqnode) { |
2086 | 2062 xmlnode querynode, x; |
2063 char *id, *from; | |
3770 | 2064 time_t now_t; |
2086 | 2065 struct tm *now; |
2066 char buf[1024]; | |
2067 | |
2068 time(&now_t); | |
2069 now = localtime(&now_t); | |
2070 | |
2071 id = xmlnode_get_attrib(iqnode, "id"); | |
2072 from = xmlnode_get_attrib(iqnode, "from"); | |
2073 | |
2074 x = jutil_iqnew(JPACKET__RESULT, NS_TIME); | |
2075 | |
2076 xmlnode_put_attrib(x, "to", from); | |
2077 xmlnode_put_attrib(x, "id", id); | |
2078 querynode = xmlnode_get_tag(x, "query"); | |
2079 | |
2080 strftime(buf, 1024, "%Y%m%dT%T", now); | |
2081 xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "utc"), buf, -1); | |
2082 strftime(buf, 1024, "%Z", now); | |
2083 xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "tz"), buf, -1); | |
2084 strftime(buf, 1024, "%d %b %Y %T", now); | |
2085 xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "display"), buf, -1); | |
3770 | 2086 |
2956 | 2087 gjab_send(gjc, x); |
2086 | 2088 |
2089 xmlnode_free(x); | |
2090 } | |
2091 | |
4538 | 2092 struct jabber_xfer_data { |
3630 | 2093 struct g_url *url; |
2094 GString *headers; | |
2095 gboolean newline; | |
4538 | 2096 |
2097 char *iq_id; | |
2098 | |
2099 struct jabber_data *jd; | |
3630 | 2100 }; |
2101 | |
6240
ac191233b816
[gaim-migrate @ 6734]
Christian Hammond <chipx86@chipx86.com>
parents:
6115
diff
changeset
|
2102 static void jabber_xfer_init(GaimXfer *xfer) |
4538 | 2103 { |
2104 struct jabber_xfer_data *data = xfer->data; | |
2105 gaim_xfer_start(xfer, -1, data->url->address, data->url->port); | |
2106 } | |
2107 | |
6240
ac191233b816
[gaim-migrate @ 6734]
Christian Hammond <chipx86@chipx86.com>
parents:
6115
diff
changeset
|
2108 static void jabber_xfer_free(GaimXfer *xfer) |
4538 | 2109 { |
2110 struct jabber_xfer_data *data = xfer->data; | |
2111 data->jd->file_transfers = g_slist_remove(data->jd->file_transfers, xfer); | |
2112 | |
2113 g_string_free(data->headers, TRUE); | |
2114 g_free(data->url); | |
2115 g_free(data->iq_id); | |
2116 g_free(data); | |
2117 | |
2118 xfer->data = NULL; | |
3630 | 2119 } |
2120 | |
6240
ac191233b816
[gaim-migrate @ 6734]
Christian Hammond <chipx86@chipx86.com>
parents:
6115
diff
changeset
|
2121 static void jabber_xfer_end(GaimXfer *xfer) |
4538 | 2122 { |
2123 struct jabber_xfer_data *data = xfer->data; | |
2124 xmlnode x; | |
2125 | |
2126 x = xmlnode_new_tag("iq"); | |
2127 xmlnode_put_attrib(x, "type", "result"); | |
2128 xmlnode_put_attrib(x, "to", xfer->who); | |
2129 xmlnode_put_attrib(x, "id", data->iq_id); | |
2130 | |
2131 gjab_send(data->jd->gjc, x); | |
2132 | |
2133 xmlnode_free(x); | |
2134 | |
2135 jabber_xfer_free(xfer); | |
2136 } | |
2137 | |
6240
ac191233b816
[gaim-migrate @ 6734]
Christian Hammond <chipx86@chipx86.com>
parents:
6115
diff
changeset
|
2138 static void jabber_xfer_start(GaimXfer *xfer) |
4538 | 2139 { |
2140 struct jabber_xfer_data *data = xfer->data; | |
2141 char *buf = g_strdup_printf("GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", | |
2142 data->url->page, data->url->address); | |
2143 write(xfer->fd, buf, strlen(buf)); | |
2144 g_free(buf); | |
2145 } | |
2146 | |
6240
ac191233b816
[gaim-migrate @ 6734]
Christian Hammond <chipx86@chipx86.com>
parents:
6115
diff
changeset
|
2147 static size_t jabber_xfer_read(char **buffer, GaimXfer *xfer) { |
4538 | 2148 struct jabber_xfer_data *data = xfer->data; |
3630 | 2149 char test; |
5435 | 2150 int size; |
4538 | 2151 |
2152 if(read(xfer->fd, &test, sizeof(test)) > 0) { | |
2153 data->headers = g_string_append_c(data->headers, test); | |
2154 if(test == '\r') | |
2155 return 0; | |
2156 if(test == '\n') { | |
2157 if(data->newline) { | |
2158 gchar *lenstr = strstr(data->headers->str, "Content-Length: "); | |
2159 if(lenstr) { | |
5435 | 2160 sscanf(lenstr, "Content-Length: %d", &size); |
4538 | 2161 gaim_xfer_set_size(xfer, size); |
2162 } | |
2163 gaim_xfer_set_read_fnc(xfer, NULL); | |
2164 return 0; | |
2165 } else | |
2166 data->newline = TRUE; | |
2167 return 0; | |
3630 | 2168 } |
4538 | 2169 data->newline = FALSE; |
2170 return 0; | |
3630 | 2171 } |
4538 | 2172 return 0; |
3630 | 2173 } |
2174 | |
6240
ac191233b816
[gaim-migrate @ 6734]
Christian Hammond <chipx86@chipx86.com>
parents:
6115
diff
changeset
|
2175 static void jabber_xfer_cancel_send(GaimXfer *xfer) { |
4675
3145c5c45877
[gaim-migrate @ 4986]
Christian Hammond <chipx86@chipx86.com>
parents:
4634
diff
changeset
|
2176 } |
3145c5c45877
[gaim-migrate @ 4986]
Christian Hammond <chipx86@chipx86.com>
parents:
4634
diff
changeset
|
2177 |
6240
ac191233b816
[gaim-migrate @ 6734]
Christian Hammond <chipx86@chipx86.com>
parents:
6115
diff
changeset
|
2178 static void jabber_xfer_cancel_recv(GaimXfer *xfer) { |
4538 | 2179 struct jabber_xfer_data *data = xfer->data; |
3630 | 2180 xmlnode x,y; |
2181 | |
2182 x = xmlnode_new_tag("iq"); | |
2183 xmlnode_put_attrib(x, "type", "error"); | |
4538 | 2184 xmlnode_put_attrib(x, "to", xfer->who); |
2185 xmlnode_put_attrib(x, "id", data->iq_id); | |
3630 | 2186 y = xmlnode_insert_tag(x, "error"); |
2187 /* FIXME: need to handle other kinds of errors here */ | |
2188 xmlnode_put_attrib(y, "code", "406"); | |
2189 xmlnode_insert_cdata(y, "File Transfer Refused", -1); | |
2190 | |
4538 | 2191 gjab_send(data->jd->gjc, x); |
3630 | 2192 |
2193 xmlnode_free(x); | |
2194 | |
4538 | 2195 jabber_xfer_free(xfer); |
3630 | 2196 } |
2197 | |
2198 static void jabber_handleoob(gjconn gjc, xmlnode iqnode) { | |
4538 | 2199 struct jabber_xfer_data *xfer_data; |
3630 | 2200 struct jabber_data *jd = GJ_GC(gjc)->proto_data; |
6240
ac191233b816
[gaim-migrate @ 6734]
Christian Hammond <chipx86@chipx86.com>
parents:
6115
diff
changeset
|
2201 GaimXfer *xfer; |
3630 | 2202 char *msg = NULL; |
4538 | 2203 char *filename; |
3630 | 2204 xmlnode querynode = xmlnode_get_tag(iqnode, "query"); |
2205 xmlnode urlnode,descnode; | |
2206 | |
2207 if(!querynode) | |
2208 return; | |
2209 urlnode = xmlnode_get_tag(querynode, "url"); | |
2210 if(!urlnode) | |
2211 return; | |
2212 descnode = xmlnode_get_tag(querynode, "desc"); | |
2213 if(descnode) | |
2214 msg = xmlnode_get_data(descnode); | |
2215 | |
4538 | 2216 xfer_data = g_new0(struct jabber_xfer_data, 1); |
2217 xfer_data->url = parse_url(xmlnode_get_data(urlnode)); | |
2218 xfer_data->jd = jd; | |
2219 xfer_data->headers = g_string_new(""); | |
2220 xfer_data->iq_id = g_strdup(xmlnode_get_attrib(iqnode, "id")); | |
2221 | |
2222 xfer = gaim_xfer_new(GJ_GC(gjc)->account, GAIM_XFER_RECEIVE, | |
2223 xmlnode_get_attrib(iqnode, "from")); | |
2224 xfer->data = xfer_data; | |
2225 | |
2226 filename = g_strdup(g_strrstr(xfer_data->url->page, "/")); | |
2227 if(!filename) | |
2228 filename = g_strdup(xfer_data->url->page); | |
2229 | |
2230 gaim_xfer_set_filename(xfer, filename); | |
2231 | |
2232 g_free(filename); | |
2233 | |
2234 gaim_xfer_set_init_fnc(xfer, jabber_xfer_init); | |
2235 gaim_xfer_set_end_fnc(xfer, jabber_xfer_end); | |
4675
3145c5c45877
[gaim-migrate @ 4986]
Christian Hammond <chipx86@chipx86.com>
parents:
4634
diff
changeset
|
2236 gaim_xfer_set_cancel_send_fnc(xfer, jabber_xfer_cancel_send); |
3145c5c45877
[gaim-migrate @ 4986]
Christian Hammond <chipx86@chipx86.com>
parents:
4634
diff
changeset
|
2237 gaim_xfer_set_cancel_recv_fnc(xfer, jabber_xfer_cancel_recv); |
4538 | 2238 gaim_xfer_set_read_fnc(xfer, jabber_xfer_read); |
2239 gaim_xfer_set_start_fnc(xfer, jabber_xfer_start); | |
2240 | |
2241 jd->file_transfers = g_slist_append(jd->file_transfers, xfer); | |
2242 | |
2243 gaim_xfer_request(xfer); | |
3630 | 2244 } |
2245 | |
2956 | 2246 static void jabber_handlelast(gjconn gjc, xmlnode iqnode) { |
3630 | 2247 xmlnode x, querytag; |
2086 | 2248 char *id, *from; |
2956 | 2249 struct jabber_data *jd = GJ_GC(gjc)->proto_data; |
2086 | 2250 char idle_time[32]; |
3630 | 2251 |
2086 | 2252 id = xmlnode_get_attrib(iqnode, "id"); |
2253 from = xmlnode_get_attrib(iqnode, "from"); | |
2254 | |
2255 x = jutil_iqnew(JPACKET__RESULT, "jabber:iq:last"); | |
2256 | |
2257 xmlnode_put_attrib(x, "to", from); | |
2258 xmlnode_put_attrib(x, "id", id); | |
2259 querytag = xmlnode_get_tag(x, "query"); | |
2260 g_snprintf(idle_time, sizeof idle_time, "%ld", jd->idle ? time(NULL) - jd->idle : 0); | |
2261 xmlnode_put_attrib(querytag, "seconds", idle_time); | |
2262 | |
2956 | 2263 gjab_send(gjc, x); |
2086 | 2264 xmlnode_free(x); |
2265 } | |
2266 | |
2956 | 2267 /* |
2268 * delete == TRUE: delete found entry | |
2269 * | |
2270 * returns pointer to (local) copy of value if found, NULL otherwise | |
2271 * | |
2272 * Note: non-reentrant! Local static storage re-used on subsequent calls. | |
2273 * If you're going to need to keep the returned value, make a copy! | |
2274 */ | |
2275 static gchar *jabber_track_queries(GHashTable *queries, gchar *key, gboolean delete) | |
2276 { | |
2277 gpointer my_key, my_val; | |
2278 static gchar *ret_val = NULL; | |
2279 | |
2280 if(ret_val != NULL) { | |
2281 g_free(ret_val); | |
2282 ret_val = NULL; | |
2283 } | |
2284 | |
2285 /* self-protection */ | |
2286 if(queries != NULL && key != NULL) { | |
2287 if(g_hash_table_lookup_extended(queries, key, &my_key, &my_val)) { | |
2288 ret_val = g_strdup((gchar *) my_val); | |
2289 if(delete) { | |
2290 g_hash_table_remove(queries, key); | |
2291 g_free(my_key); | |
2292 g_free(my_val); | |
2293 } | |
2294 } | |
2295 } | |
2296 | |
2297 return(ret_val); | |
2298 } | |
2299 | |
2300 static void jabber_handlepacket(gjconn gjc, jpacket p) | |
2086 | 2301 { |
5994 | 2302 char *id, *from, *to; |
2086 | 2303 switch (p->type) { |
2304 case JPACKET_MESSAGE: | |
2956 | 2305 jabber_handlemessage(gjc, p); |
2086 | 2306 break; |
2307 case JPACKET_PRESENCE: | |
2956 | 2308 jabber_handlepresence(gjc, p); |
2086 | 2309 break; |
2310 case JPACKET_IQ: | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2311 gaim_debug(GAIM_DEBUG_MISC, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2312 "jpacket_subtype: %d\n", jpacket_subtype(p)); |
2086 | 2313 |
2956 | 2314 id = xmlnode_get_attrib(p->x, "id"); |
2315 if (id != NULL && !strcmp(id, IQID_AUTH)) { | |
2316 jabber_handleauthresp(gjc, p); | |
2814
f4f9e5a01890
[gaim-migrate @ 2827]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2800
diff
changeset
|
2317 break; |
2086 | 2318 } |
2319 | |
2320 if (jpacket_subtype(p) == JPACKET__SET) { | |
2956 | 2321 xmlnode querynode; |
2322 querynode = xmlnode_get_tag(p->x, "query"); | |
5994 | 2323 from = xmlnode_get_attrib(p->x, "from"); |
2324 to = xmlnode_get_attrib(p->x, "to"); | |
6004 | 2325 if (NSCHECK(querynode, "jabber:iq:roster") && (!from || !strcmp(from, to))) { |
2956 | 2326 jabber_handlebuddy(gjc, xmlnode_get_firstchild(querynode)); |
3630 | 2327 } else if(NSCHECK(querynode, "jabber:iq:oob")) { |
2328 jabber_handleoob(gjc, p->x); | |
2956 | 2329 } |
2086 | 2330 } else if (jpacket_subtype(p) == JPACKET__GET) { |
3770 | 2331 xmlnode querynode; |
2086 | 2332 querynode = xmlnode_get_tag(p->x, "query"); |
3770 | 2333 if (NSCHECK(querynode, NS_VERSION)) { |
2334 jabber_handleversion(gjc, p->x); | |
2086 | 2335 } else if (NSCHECK(querynode, NS_TIME)) { |
3770 | 2336 jabber_handletime(gjc, p->x); |
2086 | 2337 } else if (NSCHECK(querynode, "jabber:iq:last")) { |
3770 | 2338 jabber_handlelast(gjc, p->x); |
2086 | 2339 } |
2340 } else if (jpacket_subtype(p) == JPACKET__RESULT) { | |
2341 xmlnode querynode, vcard; | |
2342 char *xmlns, *from; | |
2343 | |
2956 | 2344 /* |
2345 * TBD: ISTM maybe this part could use a serious re-work? | |
2346 */ | |
2086 | 2347 from = xmlnode_get_attrib(p->x, "from"); |
2348 querynode = xmlnode_get_tag(p->x, "query"); | |
2349 vcard = xmlnode_get_tag(p->x, "vCard"); | |
2316
ebb5ecb2cd5b
[gaim-migrate @ 2326]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2309
diff
changeset
|
2350 if (!vcard) |
ebb5ecb2cd5b
[gaim-migrate @ 2326]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2309
diff
changeset
|
2351 vcard = xmlnode_get_tag(p->x, "VCARD"); |
2086 | 2352 |
2353 if (NSCHECK(querynode, NS_ROSTER)) { | |
2956 | 2354 jabber_handleroster(gjc, querynode); |
2086 | 2355 } else if (NSCHECK(querynode, NS_VCARD)) { |
2956 | 2356 jabber_track_queries(gjc->queries, id, TRUE); /* delete query track */ |
3770 | 2357 jabber_handlevcard(gjc, querynode, from); |
2316
ebb5ecb2cd5b
[gaim-migrate @ 2326]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2309
diff
changeset
|
2358 } else if (vcard) { |
2956 | 2359 jabber_track_queries(gjc->queries, id, TRUE); /* delete query track */ |
2360 jabber_handlevcard(gjc, vcard, from); | |
2361 } else if((xmlns = xmlnode_get_attrib(querynode, "xmlns")) != NULL) { | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2362 gaim_debug(GAIM_DEBUG_MISC, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2363 "jabber:iq:query: %s\n", xmlns); |
2086 | 2364 } else { |
2956 | 2365 char *val; |
2366 | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2367 gaim_debug(GAIM_DEBUG_MISC, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2368 "jabber:iq: %s\n", xmlnode2str(p->x)); |
2956 | 2369 |
2370 /* handle "null" query results */ | |
2371 if((val = jabber_track_queries(gjc->queries, id, TRUE)) != NULL) { | |
2372 if(strcmp((char *) val, "vCard") == 0) { | |
2373 /* | |
2374 * No actual vCard, but there's other stuff. This | |
2375 * way the user always gets some kind of response. | |
2376 */ | |
2377 jabber_handlevcard(gjc, NULL, from); | |
3257 | 2378 } else if(!strcmp((char *) val, "change_password")) { |
2379 char buf[BUF_LONG]; | |
3311 | 2380 sprintf(buf, _("Password successfully changed.")); |
3257 | 2381 |
5436
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
2382 gaim_notify_info(GJ_GC(gjc), NULL, buf, NULL); |
2956 | 2383 } |
2384 } | |
2086 | 2385 } |
2386 | |
2387 } else if (jpacket_subtype(p) == JPACKET__ERROR) { | |
2388 xmlnode xerr; | |
2389 char *from, *errmsg = NULL; | |
2390 int errcode = 0; | |
2391 | |
2392 from = xmlnode_get_attrib(p->x, "from"); | |
2393 xerr = xmlnode_get_tag(p->x, "error"); | |
2394 if (xerr) { | |
2395 errmsg = xmlnode_get_data(xerr); | |
2396 if (xmlnode_get_attrib(xerr, "code")) | |
2397 errcode = atoi(xmlnode_get_attrib(xerr, "code")); | |
2398 } | |
2399 | |
3427 | 2400 from = g_strdup_printf("Jabber Error %d (%s)", errcode, from); |
5436
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
2401 gaim_notify_error(GJ_GC(gjc), NULL, from, errmsg); |
2086 | 2402 g_free(from); |
2403 | |
2404 } | |
2405 | |
2406 break; | |
2407 case JPACKET_S10N: | |
2956 | 2408 jabber_handles10n(gjc, p); |
2086 | 2409 break; |
2410 default: | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2411 gaim_debug(GAIM_DEBUG_MISC, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2412 "jabber: packet type %d (%s)\n", p->type, xmlnode2str(p->x)); |
2086 | 2413 } |
2414 | |
2415 xmlnode_free(p->x); | |
2416 | |
2417 return; | |
2418 } | |
2419 | |
2956 | 2420 static void jabber_handlestate(gjconn gjc, int state) |
2086 | 2421 { |
2422 switch (state) { | |
2423 case JCONN_STATE_OFF: | |
3074 | 2424 if(gjc->was_connected) { |
5572 | 2425 gaim_connection_error(GJ_GC(gjc), _("Connection lost")); |
3074 | 2426 } else { |
5572 | 2427 gaim_connection_error(GJ_GC(gjc), _("Unable to connect")); |
3074 | 2428 } |
2086 | 2429 break; |
2430 case JCONN_STATE_CONNECTED: | |
3074 | 2431 gjc->was_connected = 1; |
5572 | 2432 gaim_connection_update_progress(GJ_GC(gjc), _("Connected"), 2, JABBER_CONNECT_STEPS); |
2086 | 2433 break; |
2434 case JCONN_STATE_ON: | |
5572 | 2435 gaim_connection_update_progress(GJ_GC(gjc), _("Requesting Authentication Method"), 3, JABBER_CONNECT_STEPS); |
2956 | 2436 gjab_reqauth(gjc); |
2086 | 2437 break; |
2438 default: | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2439 gaim_debug(GAIM_DEBUG_MISC, "jabber", "state change: %d\n", state); |
2086 | 2440 } |
2441 return; | |
2442 } | |
2443 | |
5572 | 2444 static void jabber_login(GaimAccount *account) |
2086 | 2445 { |
5572 | 2446 GaimConnection *gc = gaim_account_get_connection(account); |
2086 | 2447 struct jabber_data *jd = gc->proto_data = g_new0(struct jabber_data, 1); |
4917 | 2448 char *loginname = create_valid_jid(account->username, DEFAULT_SERVER, "Gaim"); |
2086 | 2449 |
6622 | 2450 gc->flags |= GAIM_CONNECTION_HTML; |
5174 | 2451 |
3311 | 2452 jd->buddies = g_hash_table_new(g_str_hash, g_str_equal); |
2956 | 2453 jd->chats = NULL; /* we have no chats yet */ |
2086 | 2454 |
5572 | 2455 gaim_connection_update_progress(gc, _("Connecting"), 1, JABBER_CONNECT_STEPS); |
2086 | 2456 |
4491 | 2457 if (!(jd->gjc = gjab_new(loginname, account->password, gc))) { |
2086 | 2458 g_free(loginname); |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2459 gaim_debug(GAIM_DEBUG_ERROR, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2460 "unable to connect (jab_new failed)\n"); |
5572 | 2461 gaim_connection_error(gc, _("Unable to connect")); |
2086 | 2462 return; |
2463 } | |
2464 | |
2465 g_free(loginname); | |
2956 | 2466 gjab_state_handler(jd->gjc, jabber_handlestate); |
2467 gjab_packet_handler(jd->gjc, jabber_handlepacket); | |
2468 jd->gjc->queries = g_hash_table_new(g_str_hash, g_str_equal); | |
2469 gjab_start(jd->gjc); | |
2086 | 2470 } |
2471 | |
2472 static gboolean jabber_destroy_hash(gpointer key, gpointer val, gpointer data) { | |
3770 | 2473 g_free(key); |
2086 | 2474 g_free(val); |
2475 return TRUE; | |
2476 } | |
2477 | |
3311 | 2478 static gboolean jabber_destroy_buddy_hash(gpointer key, gpointer val, gpointer data) { |
2479 struct jabber_buddy_data *jbd = val; | |
2480 while (jbd->resources) { | |
2481 g_free(((jab_res_info) ((GSList *)jbd->resources)->data)->name); | |
2482 if(((jab_res_info) ((GSList *)jbd->resources)->data)->away_msg) | |
2483 g_free(((jab_res_info) ((GSList *)jbd->resources)->data)->away_msg); | |
2484 g_free(((GSList *)jbd->resources)->data); | |
2485 jbd->resources = g_slist_remove(jbd->resources, ((GSList *)jbd->resources)->data); | |
2486 | |
2487 } | |
2488 if(jbd->error_msg) | |
2489 g_free(jbd->error_msg); | |
2490 g_free(key); | |
2491 g_free(jbd); | |
2492 return TRUE; | |
2493 } | |
2494 | |
2495 | |
2086 | 2496 static gboolean jabber_free(gpointer data) |
2497 { | |
2956 | 2498 struct jabber_data *jd = data; |
2499 | |
3236 | 2500 if(jd->gjc != NULL) { |
3486 | 2501 g_free(jd->gjc->sid); |
3236 | 2502 gjab_delete(jd->gjc); |
2503 jd->gjc = NULL; | |
2504 } | |
2956 | 2505 g_free(jd); |
2506 | |
2086 | 2507 return FALSE; |
2508 } | |
2509 | |
5572 | 2510 static void jabber_close(GaimConnection *gc) |
2086 | 2511 { |
2512 struct jabber_data *jd = gc->proto_data; | |
2956 | 2513 |
2514 if(jd) { | |
2515 GSList *jcs = jd->chats; | |
2516 | |
2517 /* Free-up the jabber_chat struct allocs and the list */ | |
2518 while (jcs) { | |
3311 | 2519 gaim_jid_free(((struct jabber_chat *)jcs->data)->gjid); |
2956 | 2520 g_free(jcs->data); |
2521 jcs = jcs->next; | |
2522 } | |
2523 g_slist_free(jd->chats); | |
2524 | |
3311 | 2525 /* Free-up the buddy data hash */ |
2526 if(jd->buddies != NULL) | |
2527 { | |
2528 g_hash_table_foreach_remove(jd->buddies, jabber_destroy_buddy_hash, NULL); | |
2529 g_hash_table_destroy(jd->buddies); | |
2530 jd->buddies = NULL; | |
2956 | 2531 } |
2532 | |
2533 /* Free-up the pending queries memories and the list */ | |
3236 | 2534 if(jd->gjc != NULL && jd->gjc->queries != NULL) { |
2956 | 2535 g_hash_table_foreach_remove(jd->gjc->queries, jabber_destroy_hash, NULL); |
2536 g_hash_table_destroy(jd->gjc->queries); | |
2537 jd->gjc->queries = NULL; | |
2538 } | |
2539 } | |
2300
d2686f757d6e
[gaim-migrate @ 2310]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2289
diff
changeset
|
2540 if (gc->inpa) |
d2686f757d6e
[gaim-migrate @ 2310]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2289
diff
changeset
|
2541 gaim_input_remove(gc->inpa); |
2956 | 2542 |
2543 if(jd) { | |
3613 | 2544 g_timeout_add(0, jabber_free, jd); |
3236 | 2545 if(jd->gjc != NULL) |
2546 xmlnode_free(jd->gjc->current); | |
2956 | 2547 } |
2086 | 2548 gc->proto_data = NULL; |
2549 } | |
2550 | |
6059 | 2551 static int jabber_send_typing(GaimConnection *gc, const char *who, int typing) |
3311 | 2552 { |
2553 xmlnode x, y; | |
2554 char *realwho; | |
2555 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; | |
2556 jab_res_info jri = jabber_find_resource(gc, who); | |
2557 | |
2558 if(!jri || !jri->has_composing) | |
2559 return 0; | |
2560 | |
2561 if((realwho = get_realwho(gjc, who, FALSE, NULL)) == NULL) | |
2562 return 0; | |
3596 | 2563 |
3311 | 2564 x = xmlnode_new_tag("message"); |
2565 xmlnode_put_attrib(x, "to", realwho); | |
2566 | |
2567 y = xmlnode_insert_tag(x, "x"); | |
2568 xmlnode_put_attrib(y, "xmlns", "jabber:x:event"); | |
2569 | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5685
diff
changeset
|
2570 if(typing == GAIM_TYPING) |
3311 | 2571 xmlnode_insert_tag(y, "composing"); |
3596 | 2572 |
3311 | 2573 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); |
2574 xmlnode_free(x); | |
2575 g_free(realwho); | |
2576 return JABBER_TYPING_NOTIFY_INT; | |
2577 } | |
2578 | |
5093 | 2579 static void insert_message(xmlnode x, const char *message, gboolean use_xhtml) { |
2580 xmlnode y; | |
5110 | 2581 char *buf = g_strdup_printf("<html xmlns='http://jabber.org/protocol/xhtml-im'><body>%s</body></html>", message); |
2582 char *xhtml, *plain; | |
2583 | |
2584 html_to_xhtml(buf, &xhtml, &plain); | |
2585 g_free(buf); | |
2586 | |
5093 | 2587 y = xmlnode_insert_tag(x, "body"); |
5110 | 2588 xmlnode_insert_cdata(y, plain, -1); |
2589 g_free(plain); | |
5093 | 2590 |
2591 if(use_xhtml) { | |
5110 | 2592 y = xmlnode_str(xhtml, strlen(xhtml)); |
5093 | 2593 if(y) { |
2594 xmlnode_insert_tag_node(x, y); | |
2595 xmlnode_free(y); | |
2596 } else { | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2597 gaim_debug(GAIM_DEBUG_ERROR, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2598 "holy cow, html_to_xhtml didn't work right!\n"); |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2599 gaim_debug(GAIM_DEBUG_ERROR, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
2600 "the invalid XML: %s\n", xhtml); |
5093 | 2601 } |
2602 } | |
5110 | 2603 g_free(xhtml); |
5093 | 2604 } |
2605 | |
6622 | 2606 static int jabber_send_im(GaimConnection *gc, const char *who, const char *message, int len, GaimImFlags flags) |
2086 | 2607 { |
2608 xmlnode x, y; | |
3311 | 2609 char *thread_id = NULL; |
2956 | 2610 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
5093 | 2611 jab_res_info jri = jabber_find_resource(gc, who); |
2086 | 2612 |
2613 if (!who || !message) | |
2123
56c4382f2909
[gaim-migrate @ 2133]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2112
diff
changeset
|
2614 return 0; |
2086 | 2615 |
2616 x = xmlnode_new_tag("message"); | |
4927 | 2617 xmlnode_put_attrib(x, "to", who); |
2618 | |
2619 thread_id = jabber_get_convo_thread(gjc, who); | |
3311 | 2620 if(thread_id) |
2621 { | |
3769 | 2622 if(strcmp(thread_id, "")) { |
2623 y = xmlnode_insert_tag(x, "thread"); | |
2624 xmlnode_insert_cdata(y, thread_id, -1); | |
2625 } | |
3311 | 2626 g_free(thread_id); |
2627 } | |
2628 | |
2086 | 2629 xmlnode_put_attrib(x, "type", "chat"); |
2630 | |
3311 | 2631 /* let other clients know we support typing notification */ |
2632 y = xmlnode_insert_tag(x, "x"); | |
2633 xmlnode_put_attrib(y, "xmlns", "jabber:x:event"); | |
2634 xmlnode_insert_tag(y, "composing"); | |
2635 | |
2086 | 2636 if (message && strlen(message)) { |
5093 | 2637 insert_message(x, message, jri ? jri->has_xhtml : TRUE); |
2086 | 2638 } |
2639 | |
2956 | 2640 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); |
2086 | 2641 xmlnode_free(x); |
2303
f5bf315e6104
[gaim-migrate @ 2313]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2300
diff
changeset
|
2642 return 1; |
2086 | 2643 } |
2644 | |
3105 | 2645 /* |
2646 * Add/update buddy's roster entry on server | |
3349 | 2647 * |
2648 * If "alias" or "group" are NULL, gets them from Gaim's current buddylist values | |
2649 * for the buddy. | |
3105 | 2650 */ |
5572 | 2651 static void jabber_roster_update(GaimConnection *gc, const char *name, const char *alias, const char *group) |
3105 | 2652 { |
2653 xmlnode x, y; | |
2654 char *realwho; | |
2655 gjconn gjc; | |
6695 | 2656 GaimBuddy *buddy = NULL; |
2657 GaimGroup *buddy_group = NULL; | |
3867 | 2658 const char *my_alias = NULL; |
2659 const char *my_group = NULL; | |
3770 | 2660 |
3105 | 2661 if(gc && gc->proto_data && ((struct jabber_data *)gc->proto_data)->gjc && name) { |
3311 | 2662 gaim_jid gjid; |
3105 | 2663 gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
2664 | |
3311 | 2665 if((realwho = get_realwho(gjc, name, FALSE, &gjid)) == NULL) |
2666 return; | |
2667 | |
2668 /* FIXME: transport */ | |
2669 if(gjid->user == NULL) { | |
2670 g_free(realwho); | |
2671 gaim_jid_free(gjid); | |
2672 return; | |
3105 | 2673 } |
3311 | 2674 gaim_jid_free(gjid); |
3105 | 2675 |
2676 x = jutil_iqnew(JPACKET__SET, NS_ROSTER); | |
2677 y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item"); | |
2678 xmlnode_put_attrib(y, "jid", realwho); | |
2679 | |
4687 | 2680 buddy = gaim_find_buddy(gc->account, realwho); |
4349 | 2681 |
3349 | 2682 /* |
2683 * See if there's an explict (new?) alias for the buddy or we can pull | |
2684 * one out of current Gaim buddylist data for him. | |
2685 */ | |
2686 if(alias && alias[0] != '\0') { | |
2687 my_alias = alias; | |
4705 | 2688 } else if(buddy && buddy->alias) { |
4227 | 2689 my_alias = buddy->alias; |
3349 | 2690 } |
2691 | |
2692 /* If there's an alias for the buddy, it's not 0-length | |
3105 | 2693 * and it doesn't match his JID, add the "name" attribute. |
2694 */ | |
3349 | 2695 if(my_alias != NULL && my_alias[0] != '\0' && strcmp(realwho, my_alias)) |
3311 | 2696 { |
3642 | 2697 xmlnode_put_attrib(y, "name", my_alias); |
3105 | 2698 } |
2699 | |
2700 /* | |
3349 | 2701 * See if there's an explict (new?) group for the buddy or pull |
2702 * one out of current Gaim buddylist data for him. | |
3105 | 2703 */ |
3349 | 2704 if(group && group[0] != '\0') { |
2705 my_group = group; | |
4687 | 2706 } else if((buddy_group = gaim_find_buddys_group(buddy)) != NULL) { |
3349 | 2707 my_group = buddy_group->name; |
2708 } | |
2709 | |
2710 /* | |
2711 * Send what group the buddy's in along with the roster item. | |
2712 */ | |
2713 if(my_group != NULL && my_group[0] != '\0') { | |
2714 xmlnode z = xmlnode_insert_tag(y, "group"); | |
2715 xmlnode_insert_cdata(z, my_group, -1); | |
3105 | 2716 } |
2717 | |
2718 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); | |
2719 | |
2720 xmlnode_free(x); | |
2721 g_free(realwho); | |
2722 } | |
2723 } | |
2724 | |
3136 | 2725 /* |
3349 | 2726 * Add/update buddy's alias on server |
2727 * | |
2728 * This is just a roster update using existing, local buddylist data | |
2729 */ | |
5572 | 2730 static void jabber_alias_buddy(GaimConnection *gc, const char *name, const char *alias) |
3349 | 2731 { |
4269 | 2732 jabber_roster_update(gc, name, alias, NULL); |
3349 | 2733 } |
2734 | |
2735 /* | |
3136 | 2736 * Change buddy's group on server roster |
2737 */ | |
5572 | 2738 static void jabber_group_change(GaimConnection *gc, const char *name, const char *old_group, const char *new_group) |
3136 | 2739 { |
3349 | 2740 if(old_group && new_group && strcmp(old_group, new_group)) |
2741 jabber_roster_update(gc, name, NULL, new_group); | |
2742 } | |
2743 | |
2744 /* | |
2745 * Group rename | |
2746 * | |
2747 * Jabber doesn't have "groups," per se. "Group" is simply a JID attribute. | |
2748 * So we iterate through the list of buddies that are in the group and change | |
2749 * the group attribute for each of them. | |
2750 */ | |
5572 | 2751 static void jabber_rename_group(GaimConnection *gc, |
3867 | 2752 const char *old_group, |
2753 const char *new_group, | |
3349 | 2754 GList *members) |
2755 { | |
2756 if(old_group && new_group && strcmp(old_group, new_group)) | |
2757 while(members) { | |
2758 jabber_group_change(gc, (char *)(members->data), old_group, new_group); | |
2759 members = members->next; | |
2760 } | |
3136 | 2761 } |
2762 | |
6787
faa491042c66
[gaim-migrate @ 7326]
Christian Hammond <chipx86@chipx86.com>
parents:
6768
diff
changeset
|
2763 static void jabber_add_buddy(GaimConnection *gc, const char *name, GaimGroup *group) |
2086 | 2764 { |
3136 | 2765 xmlnode x; |
2086 | 2766 char *realwho; |
2956 | 2767 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
3311 | 2768 gaim_jid gjid; |
5572 | 2769 GaimAccount *account = gaim_connection_get_account(gc); |
2086 | 2770 |
2771 if (!((struct jabber_data *)gc->proto_data)->did_import) | |
2772 return; | |
2773 | |
3311 | 2774 /* |
2775 * If there's no name or the name is ourself | |
2776 */ | |
5572 | 2777 if(!name || !strcmp(gaim_account_get_username(account), name)) |
2086 | 2778 return; |
2779 | |
3311 | 2780 if((realwho = get_realwho(gjc, name, FALSE, &gjid)) == NULL) { |
3427 | 2781 char *msg = g_strdup_printf(_("The user %s is an invalid Jabber I.D. and was " |
2782 "therefore not added."), name); | |
5436
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
2783 gaim_notify_error(gc, NULL, _("Unable to add buddy."), |
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
2784 _("Jabber Error")); |
3311 | 2785 g_free(msg); |
2786 jabber_remove_gaim_buddy(gc, name); | |
2787 return; | |
2086 | 2788 } |
2789 | |
3311 | 2790 /* FIXME: transport */ |
2791 if(gjid->user == NULL) { | |
2792 g_free(realwho); | |
2793 gaim_jid_free(gjid); | |
2794 return; | |
2795 } | |
2796 gaim_jid_free(gjid); | |
2797 | |
2086 | 2798 x = xmlnode_new_tag("presence"); |
2799 xmlnode_put_attrib(x, "to", realwho); | |
2800 xmlnode_put_attrib(x, "type", "subscribe"); | |
2956 | 2801 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); |
2802 xmlnode_free(x); | |
2086 | 2803 |
3349 | 2804 jabber_roster_update(gc, realwho, NULL, NULL); |
3105 | 2805 |
2086 | 2806 g_free(realwho); |
2807 } | |
2808 | |
6059 | 2809 static void jabber_remove_buddy(GaimConnection *gc, const char *name, const char *group) |
2086 | 2810 { |
3048 | 2811 xmlnode x; |
2086 | 2812 char *realwho; |
2956 | 2813 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
2086 | 2814 |
3311 | 2815 if(!name || (realwho = get_realwho(gjc, name, FALSE, NULL)) == NULL) |
2086 | 2816 return; |
2817 | |
2956 | 2818 x = xmlnode_new_tag("presence"); |
2819 xmlnode_put_attrib(x, "to", realwho); | |
2820 xmlnode_put_attrib(x, "type", "unsubscribe"); | |
2821 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); | |
2086 | 2822 g_free(realwho); |
2823 xmlnode_free(x); | |
2824 } | |
2825 | |
4916 | 2826 #if 0 /* Faceprint! Look here! */ |
3314 | 2827 /* |
2828 * Remove a buddy item from the roster entirely | |
2829 */ | |
5572 | 2830 static void jabber_remove_buddy_roster_item(GaimConnection *gc, char *name) |
3314 | 2831 { |
3340 | 2832 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
3314 | 2833 char *realwho; |
3340 | 2834 |
2835 if((realwho = get_realwho(gjc, name, FALSE, NULL)) != NULL) { | |
2836 xmlnode x = jutil_iqnew(JPACKET__SET, NS_ROSTER); | |
2837 xmlnode y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item"); | |
2838 xmlnode_put_attrib(y, "jid", realwho); | |
2839 xmlnode_put_attrib(y, "subscription", "remove"); | |
2840 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); | |
2841 g_free(realwho); | |
2842 xmlnode_free(x); | |
2843 } | |
2844 } | |
4916 | 2845 #endif |
3340 | 2846 |
2847 /* | |
2848 * Unsubscribe a buddy from our presence | |
2849 */ | |
5572 | 2850 static void jabber_unsubscribe_buddy_from_us(GaimConnection *gc, const char *name) |
3340 | 2851 { |
2852 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; | |
2853 char *realwho; | |
2854 | |
2855 if((realwho = get_realwho(gjc, name, FALSE, NULL)) != NULL) { | |
2856 xmlnode g = xmlnode_new_tag("presence"); | |
2857 xmlnode_put_attrib(g, "to", realwho); | |
2858 xmlnode_put_attrib(g, "type", "unsubscribed"); | |
2859 gjab_send(gjc, g); | |
2860 xmlnode_free(g); | |
2861 } | |
2862 } | |
2863 | |
2864 /* | |
2865 * Common code for setting ourselves invisible/visible to buddy | |
2866 */ | |
5572 | 2867 static void jabber_invisible_to_buddy_common(GaimConnection *gc, const char *name, gboolean invisible) |
3340 | 2868 { |
3314 | 2869 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
3340 | 2870 char *realwho; |
2871 | |
2872 if((realwho = get_realwho(gjc, name, FALSE, NULL)) != NULL) { | |
5135 | 2873 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, realwho, TRUE); |
3340 | 2874 xmlnode g = xmlnode_new_tag("presence"); |
2875 | |
2876 xmlnode_put_attrib(g, "to", realwho); | |
2877 | |
2878 if(invisible) | |
2879 xmlnode_put_attrib(g, "type", "invisible"); | |
2880 | |
2881 gjab_send(gjc, g); | |
2882 | |
2883 g_free(realwho); | |
2884 xmlnode_free(g); | |
2885 | |
2886 if(jbd) { | |
2887 if(invisible) { | |
2888 jbd->invisible |= JABBER_BUD_INVIS; | |
2889 } else { | |
2890 jbd->invisible &= ~JABBER_BUD_INVIS; | |
2891 } | |
2892 } | |
2893 } | |
2894 } | |
2895 | |
2896 /* | |
2897 * Make ourselves temporarily invisible to a buddy | |
2898 */ | |
5572 | 2899 static void jabber_invisible_to_buddy(GaimConnection *gc, const char *name) |
3340 | 2900 { |
2901 jabber_invisible_to_buddy_common(gc, name, TRUE); | |
2902 } | |
2903 | |
2904 /* | |
2905 * Make ourselves visible to a buddy | |
2906 */ | |
5572 | 2907 static void jabber_visible_to_buddy(GaimConnection *gc, const char *name) |
3340 | 2908 { |
2909 jabber_invisible_to_buddy_common(gc, name, FALSE); | |
2910 } | |
2911 | |
2912 /* | |
2913 * Function used by the g_hash_table_foreach() in invisible_to_all_buddies() to | |
2914 * actually set the status. | |
2915 * | |
2916 * key is unused | |
2917 * value is the pointer to the jabber_buddy_data struct | |
2918 * data is gboolean: TRUE (invisible) or FALSE (not invisible) | |
2919 */ | |
2920 static void set_invisible_to_buddy_status(gpointer key, gpointer val, gpointer data) { | |
2921 struct jabber_buddy_data *jbd = val; | |
6478
338147ea6896
[gaim-migrate @ 6991]
Christian Hammond <chipx86@chipx86.com>
parents:
6371
diff
changeset
|
2922 gboolean invisible = GPOINTER_TO_INT(data); |
3340 | 2923 |
2924 if(jbd) { | |
2925 if(invisible) { | |
2926 jbd->invisible = JABBER_SERV_INVIS | JABBER_BUD_INVIS; | |
2927 } else { | |
2928 /* | |
2929 * If we've asserted server-level invisibility, cancelling | |
2930 * it removes explicit buddy invisibility settings too. | |
2931 */ | |
2932 if(jbd->invisible & JABBER_SERV_INVIS) | |
2933 jbd->invisible = JABBER_NOT_INVIS; | |
2934 } | |
2935 } | |
2936 } | |
2937 | |
2938 /* | |
2939 * Show we've set ourselves invisible/visible to all buddies on the server | |
2940 * | |
2941 * Used when we set server-wide invisibility so that individual buddy menu | |
2942 * entries show the proper option. | |
2943 */ | |
5572 | 2944 static void invisible_to_all_buddies(GaimConnection *gc, gboolean invisible) |
3340 | 2945 { |
2946 struct jabber_data *jd = gc->proto_data; | |
2947 | |
2948 if(jd->buddies != NULL) | |
6478
338147ea6896
[gaim-migrate @ 6991]
Christian Hammond <chipx86@chipx86.com>
parents:
6371
diff
changeset
|
2949 g_hash_table_foreach(jd->buddies, set_invisible_to_buddy_status, GINT_TO_POINTER(invisible)); |
3314 | 2950 } |
2951 | |
6695 | 2952 static const char *jabber_list_icon(GaimAccount *a, GaimBuddy *b) |
2086 | 2953 { |
4687 | 2954 return "jabber"; |
2955 } | |
4916 | 2956 |
6695 | 2957 static void jabber_list_emblems(GaimBuddy *b, char **se, char **sw, char **nw, char **ne) |
4916 | 2958 { |
5135 | 2959 struct jabber_buddy_data *jbd = jabber_find_buddy(b->account->gc, b->name, FALSE); |
2960 | |
2961 if(!GAIM_BUDDY_IS_ONLINE(b)) { | |
2962 if (jbd && jbd->error_msg) | |
4927 | 2963 *nw = "error"; |
5135 | 2964 |
2965 if(jbd && (jbd->subscription & JABBER_SUB_PENDING || | |
2966 !(jbd->subscription & JABBER_SUB_TO))) | |
2967 *se = "notauthorized"; | |
2968 else | |
2969 *se = "offline"; | |
2970 | |
4916 | 2971 } else { |
2972 switch (b->uc) { | |
2973 case UC_AWAY: | |
2974 *se = "away"; | |
2975 break; | |
2976 case UC_CHAT: | |
2977 *se = "chat"; | |
2978 break; | |
2979 case UC_XA: | |
2980 *se = "extendedaway"; | |
2981 break; | |
2982 case UC_DND: | |
2983 *se = "dnd"; | |
2984 break; | |
2985 case UC_ERROR: | |
2986 *se = "error"; | |
2987 break; | |
2988 } | |
2086 | 2989 } |
4916 | 2990 } |
2086 | 2991 |
5572 | 2992 static GList *jabber_chat_info(GaimConnection *gc) |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2993 { |
2956 | 2994 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
2995 | |
2996 static char *confserv = NULL; /* this pointer must be persistent */ | |
2997 gchar *server; | |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2998 |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
2999 GList *m = NULL; |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3000 struct proto_chat_entry *pce; |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3001 |
2956 | 3002 /* This is a scientific wild-ass guess... |
3003 * | |
3004 * If there are more than two "components" to the current server name, | |
3005 * lop-off the left-most component and replace with "conference." | |
3006 */ | |
3007 if(confserv != NULL) { | |
3008 g_free(confserv); /* dispose of the old value */ | |
3009 } | |
3010 | |
3011 if((server = g_strdup(gjc->user->server)) == NULL) { | |
3012 confserv = g_strdup(DEFAULT_GROUPCHAT); | |
3013 } else { | |
3014 gchar **splits, **index; | |
3015 gchar *tmp; | |
3016 int cnt = 0; | |
3017 | |
3018 | |
3019 index = splits = g_strsplit(server, ".", -1); /* split the connected server */ | |
3020 | |
3021 while(*(index++)) /* index to the end--counting the parts */ | |
3022 ++cnt; | |
3023 | |
3024 /* | |
3025 * If we've more than two parts, point to the second part. Else point | |
3026 * to the start. | |
3027 */ | |
3028 if(cnt > 2) { | |
3029 index -= cnt; | |
3030 } else { | |
3031 index = splits; | |
3032 } | |
3033 | |
3034 /* Put it together */ | |
3035 confserv = g_strjoin(".", "conference", (tmp = g_strjoinv(".", index)), NULL); | |
3036 | |
3037 g_free(server); /* we don't need this stuff no more */ | |
3038 g_free(tmp); | |
3039 g_strfreev(splits); | |
3040 } | |
3041 | |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3042 pce = g_new0(struct proto_chat_entry, 1); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3043 pce->label = _("Room:"); |
5234 | 3044 pce->identifier = "room"; |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3045 m = g_list_append(m, pce); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3046 |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3047 pce = g_new0(struct proto_chat_entry, 1); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3048 pce->label = _("Server:"); |
5234 | 3049 pce->identifier = "server"; |
2956 | 3050 pce->def = confserv; |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3051 m = g_list_append(m, pce); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3052 |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3053 pce = g_new0(struct proto_chat_entry, 1); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3054 pce->label = _("Handle:"); |
5234 | 3055 pce->identifier = "handle"; |
2956 | 3056 pce->def = gjc->user->user; |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3057 m = g_list_append(m, pce); |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3058 |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3059 return m; |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3060 } |
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3061 |
5572 | 3062 static void jabber_join_chat(GaimConnection *gc, GHashTable *data) |
2086 | 3063 { |
3064 xmlnode x; | |
5234 | 3065 char *room, *server, *handle; |
2086 | 3066 char *realwho; |
2956 | 3067 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
3068 GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats; | |
2086 | 3069 struct jabber_chat *jc; |
3311 | 3070 gaim_jid gjid; |
2086 | 3071 |
5234 | 3072 room = g_hash_table_lookup(data, "room"); |
3073 server = g_hash_table_lookup(data, "server"); | |
3074 handle = g_hash_table_lookup(data, "handle"); | |
3075 | |
3076 if (!room || !server || !handle) | |
2086 | 3077 return; |
3078 | |
5234 | 3079 realwho = create_valid_jid(room, server, handle); |
3080 gaim_debug(GAIM_DEBUG_INFO, "jabber", "%s\n", realwho); | |
2086 | 3081 |
3311 | 3082 if((gjid = gaim_jid_new(realwho)) == NULL) { |
3427 | 3083 char *msg = g_strdup_printf("The Jabber I.D. %s is invalid.", realwho); |
5436
ad445074d239
[gaim-migrate @ 5818]
Christian Hammond <chipx86@chipx86.com>
parents:
5435
diff
changeset
|
3084 gaim_notify_error(gc, NULL, _("Unable to join chat"), msg); |
3236 | 3085 g_free(msg); |
3311 | 3086 g_free(realwho); |
3236 | 3087 return; |
3088 } | |
2956 | 3089 |
3311 | 3090 if((jc = find_any_chat(gc, gjid)) != NULL) { |
2956 | 3091 switch(jc->state) { |
3092 case JCS_PENDING: | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
3093 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
3094 "attempt to re-join already pending Jabber chat! (ignoring)\n"); |
2956 | 3095 g_free(realwho); /* yuck! */ |
3311 | 3096 gaim_jid_free(gjid); |
2956 | 3097 return; |
3098 case JCS_ACTIVE: | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
3099 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
3100 "attempt to re-join already active Jabber chat! (ignoring)\n"); |
2956 | 3101 g_free(realwho); /* yuck! */ |
3311 | 3102 gaim_jid_free(gjid); |
2956 | 3103 return; |
3104 case JCS_CLOSED: | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
3105 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
3106 "rejoining previously closed Jabber chat\n"); |
2956 | 3107 break; |
3108 default: | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
3109 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
3110 "found Jabber chat in unknown state! (ignoring)\n"); |
2956 | 3111 g_free(realwho); /* yuck! */ |
3311 | 3112 gaim_jid_free(gjid); |
2956 | 3113 return; |
3114 } | |
3115 } else { | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
3116 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
3117 "joining completely new Jabber chat\n"); |
2956 | 3118 jc = g_new0(struct jabber_chat, 1); |
3311 | 3119 jc->gjid = gjid; |
2956 | 3120 jc->gc = gc; |
3121 ((struct jabber_data *)gc->proto_data)->chats = g_slist_append(jcs, jc); | |
4687 | 3122 // add_buddy(gc->account, _("Chats"), realwho, realwho); |
2956 | 3123 } |
3124 | |
3125 jc->state = JCS_PENDING; | |
3126 | |
2086 | 3127 x = jutil_presnew(0, realwho, NULL); |
2956 | 3128 gjab_send(gjc, x); |
2086 | 3129 xmlnode_free(x); |
3130 g_free(realwho); | |
3131 } | |
3132 | |
5572 | 3133 static void jabber_chat_invite(GaimConnection *gc, int id, const char *message, const char *name) |
2086 | 3134 { |
3135 xmlnode x, y; | |
3136 struct jabber_data *jd = gc->proto_data; | |
2956 | 3137 gjconn gjc = jd->gjc; |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3138 struct jabber_chat *jc = NULL; |
2086 | 3139 char *realwho, *subject; |
3140 | |
3311 | 3141 if(!name || (realwho = get_realwho(gjc, name, FALSE, NULL)) == NULL) |
2086 | 3142 return; |
3143 | |
3144 /* find which chat we're inviting to */ | |
2956 | 3145 if(jabber_find_chat_by_convo_id(gc, id, &jc) != 0) |
2086 | 3146 return; |
3147 | |
3148 x = xmlnode_new_tag("message"); | |
3149 xmlnode_put_attrib(x, "to", realwho); | |
3311 | 3150 |
2086 | 3151 g_free(realwho); |
3152 | |
3153 y = xmlnode_insert_tag(x, "x"); | |
3154 xmlnode_put_attrib(y, "xmlns", "jabber:x:conference"); | |
3311 | 3155 subject = g_strdup_printf("%s@%s", jc->gjid->user, jc->gjid->server); |
2086 | 3156 xmlnode_put_attrib(y, "jid", subject); |
3157 g_free(subject); | |
3158 | |
3159 if (message && strlen(message)) { | |
5093 | 3160 insert_message(x, message, FALSE); |
2086 | 3161 } |
3162 | |
2956 | 3163 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); |
2086 | 3164 xmlnode_free(x); |
3165 } | |
3166 | |
5572 | 3167 static void jabber_chat_leave(GaimConnection *gc, int id) |
2086 | 3168 { |
3169 struct jabber_data *jd = gc->proto_data; | |
2956 | 3170 gjconn gjc = jd->gjc; |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3171 struct jabber_chat *jc = NULL; |
3311 | 3172 char *chatname; |
2086 | 3173 xmlnode x; |
3174 | |
2956 | 3175 /* Find out which chat we're leaving */ |
3176 if(jabber_find_chat_by_convo_id(gc, id, &jc) != 0) | |
2086 | 3177 return; |
3178 | |
3311 | 3179 chatname = g_strdup_printf("%s@%s", jc->gjid->user, jc->gjid->server); |
3180 x = jutil_presnew(0, chatname, NULL); | |
3181 g_free(chatname); | |
2086 | 3182 xmlnode_put_attrib(x, "type", "unavailable"); |
2956 | 3183 gjab_send(gjc, x); |
2086 | 3184 xmlnode_free(x); |
3185 jc->b = NULL; | |
3186 } | |
3187 | |
6059 | 3188 static int jabber_chat_send(GaimConnection *gc, int id, const char *message) |
2086 | 3189 { |
3190 xmlnode x, y; | |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3191 struct jabber_chat *jc = NULL; |
2086 | 3192 char *chatname; |
2956 | 3193 int retval = 0; |
3194 | |
3195 /* Find out which chat we're sending to */ | |
3196 if((retval = jabber_find_chat_by_convo_id(gc, id, &jc)) != 0) | |
3197 return(retval); | |
2086 | 3198 |
3199 x = xmlnode_new_tag("message"); | |
3311 | 3200 xmlnode_put_attrib(x, "from", jc->gjid->full); |
3201 chatname = g_strdup_printf("%s@%s", jc->gjid->user, jc->gjid->server); | |
2086 | 3202 xmlnode_put_attrib(x, "to", chatname); |
3203 g_free(chatname); | |
3204 xmlnode_put_attrib(x, "type", "groupchat"); | |
3205 | |
2289
38e156136896
[gaim-migrate @ 2299]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2278
diff
changeset
|
3206 if (message && strlen(message) > strlen("/topic ") && |
4793 | 3207 !g_ascii_strncasecmp(message, "/topic ", strlen("/topic "))) { |
2289
38e156136896
[gaim-migrate @ 2299]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2278
diff
changeset
|
3208 char buf[8192]; |
38e156136896
[gaim-migrate @ 2299]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2278
diff
changeset
|
3209 y = xmlnode_insert_tag(x, "subject"); |
3642 | 3210 xmlnode_insert_cdata(y, message + strlen("/topic "), -1); |
2289
38e156136896
[gaim-migrate @ 2299]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2278
diff
changeset
|
3211 y = xmlnode_insert_tag(x, "body"); |
3642 | 3212 g_snprintf(buf, sizeof(buf), "/me has changed the subject to: %s", message + strlen("/topic")); |
2289
38e156136896
[gaim-migrate @ 2299]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2278
diff
changeset
|
3213 xmlnode_insert_cdata(y, buf, -1); |
38e156136896
[gaim-migrate @ 2299]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2278
diff
changeset
|
3214 } else if (message && strlen(message)) { |
5093 | 3215 insert_message(x, message, FALSE); |
2086 | 3216 } |
3217 | |
2956 | 3218 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); |
2086 | 3219 xmlnode_free(x); |
2167
edf8c5a70e5b
[gaim-migrate @ 2177]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2162
diff
changeset
|
3220 return 0; |
2086 | 3221 } |
3222 | |
6059 | 3223 static void jabber_chat_whisper(GaimConnection *gc, int id, const char *who, const char *message) |
2086 | 3224 { |
5093 | 3225 xmlnode x; |
2205
cff4fbe01c7b
[gaim-migrate @ 2215]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2170
diff
changeset
|
3226 struct jabber_chat *jc = NULL; |
2086 | 3227 char *chatname; |
3228 | |
2956 | 3229 /* Find out which chat we're whispering to */ |
3230 if(jabber_find_chat_by_convo_id(gc, id, &jc) != 0) | |
2086 | 3231 return; |
3232 | |
3233 x = xmlnode_new_tag("message"); | |
3311 | 3234 xmlnode_put_attrib(x, "from", jc->gjid->full); |
3235 chatname = g_strdup_printf("%s@%s/%s", jc->gjid->user, jc->gjid->server, who); | |
2086 | 3236 xmlnode_put_attrib(x, "to", chatname); |
3237 g_free(chatname); | |
3238 xmlnode_put_attrib(x, "type", "normal"); | |
3239 | |
3240 if (message && strlen(message)) { | |
5093 | 3241 insert_message(x, message, FALSE); |
2086 | 3242 } |
3243 | |
2956 | 3244 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x); |
2086 | 3245 xmlnode_free(x); |
3246 } | |
3247 | |
3248 static char *jabber_normalize(const char *s) | |
3249 { | |
3250 static char buf[BUF_LEN]; | |
3251 char *t, *u; | |
3252 int x = 0; | |
3253 | |
3254 g_return_val_if_fail((s != NULL), NULL); | |
3255 | |
2956 | 3256 /* Somebody called us with s == NULL once... */ |
3257 if(s == NULL) { | |
3258 return(NULL); | |
3259 } else { | |
4793 | 3260 u = t = g_utf8_strdown(s, -1); |
2956 | 3261 |
3262 while (*t && (x < BUF_LEN - 1)) { | |
3263 if (*t != ' ') | |
3264 buf[x++] = *t; | |
3265 t++; | |
3266 } | |
3267 buf[x] = '\0'; | |
3268 g_free(u); | |
3269 | |
3270 if (!strchr(buf, '@')) { | |
4927 | 3271 strcat(buf, "@" DEFAULT_SERVER); /* this isn't always right, but eh */ |
2956 | 3272 } else if ((u = strchr(strchr(buf, '@'), '/')) != NULL) { |
3273 *u = '\0'; | |
3274 } | |
3275 | |
3276 return buf; | |
2086 | 3277 } |
3278 } | |
3279 | |
5572 | 3280 static void jabber_get_info(GaimConnection *gc, const char *who) { |
2086 | 3281 xmlnode x; |
3282 char *id; | |
2956 | 3283 char *realwho; |
2086 | 3284 struct jabber_data *jd = gc->proto_data; |
2956 | 3285 gjconn gjc = jd->gjc; |
2086 | 3286 |
3311 | 3287 if((realwho = get_realwho(gjc, who, TRUE, NULL)) == NULL) |
3288 return; | |
3289 | |
2086 | 3290 x = jutil_iqnew(JPACKET__GET, NS_VCARD); |
2956 | 3291 xmlnode_put_attrib(x, "to", realwho); |
3311 | 3292 |
2956 | 3293 g_free(realwho); |
3294 | |
3295 id = gjab_getid(gjc); | |
2086 | 3296 xmlnode_put_attrib(x, "id", id); |
3297 | |
2956 | 3298 g_hash_table_insert(jd->gjc->queries, g_strdup(id), g_strdup("vCard")); |
3299 | |
3300 gjab_send(gjc, x); | |
2086 | 3301 |
3302 xmlnode_free(x); | |
3311 | 3303 } |
3304 | |
5572 | 3305 static void jabber_get_error_msg(GaimConnection *gc, const char *who) { |
3311 | 3306 struct jabber_data *jd = gc->proto_data; |
3307 gjconn gjc = jd->gjc; | |
3308 gchar **str_arr = (gchar **) g_new(gpointer, 3); | |
3309 gchar **ap = str_arr; | |
3310 gchar *realwho, *final; | |
3311 struct jabber_buddy_data *jbd; | |
3312 | |
3313 if((realwho = get_realwho(gjc, who, FALSE, NULL)) == NULL) { | |
3314 g_strfreev(str_arr); | |
3315 return; | |
3316 } | |
3317 | |
5135 | 3318 jbd = jabber_find_buddy(gc, realwho, TRUE); |
3311 | 3319 |
5236 | 3320 *ap++ = g_strdup_printf("<B>%s:</B> %s<BR>\n", _("Jabber ID"), realwho); |
3321 *ap++ = g_strdup_printf("<B>%s:</B> %s<BR>\n", _("Error"), jbd->error_msg); | |
3311 | 3322 *ap = NULL; |
3770 | 3323 |
3311 | 3324 final= g_strjoinv(NULL, str_arr); |
3770 | 3325 |
3311 | 3326 g_strfreev(str_arr); |
3327 | |
3328 g_show_info_text(gc, realwho, 2, final, NULL); | |
3329 g_free(realwho); | |
3330 g_free(final); | |
2086 | 3331 } |
3332 | |
5572 | 3333 static void jabber_get_away_msg(GaimConnection *gc, const char *who) { |
2956 | 3334 struct jabber_data *jd = gc->proto_data; |
3335 gjconn gjc = jd->gjc; | |
3311 | 3336 int num_resources; |
3337 gaim_jid gjid; | |
3338 char *buddy = get_realwho(gjc, who, FALSE, &gjid); | |
5135 | 3339 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, buddy, TRUE); |
3311 | 3340 gchar **str_arr; |
3341 gchar **ap; | |
3342 gchar *realwho, *final; | |
3343 GSList *resources; | |
3344 int i; | |
3345 | |
3346 if(!buddy) | |
3347 return; | |
3348 | |
3349 if(!gjid->resource) { | |
3350 num_resources = g_slist_length(jbd->resources); | |
3351 resources = jbd->resources; | |
3352 } else { | |
3353 num_resources = 1; | |
3354 resources = jbd->resources; | |
3355 while(strcasecmp(((jab_res_info)resources->data)->name, gjid->resource)) | |
3356 resources = resources->next; | |
3357 } | |
3358 | |
3359 gaim_jid_free(gjid); | |
2956 | 3360 |
3361 /* space for all elements: Jabber I.D. + "status" + NULL (list terminator) */ | |
3311 | 3362 str_arr = (gchar **) g_new(gpointer, num_resources*2 + 1); |
3363 ap = str_arr; | |
3364 | |
3365 for(i=0; i<num_resources; i++) | |
3366 { | |
3367 jab_res_info jri = resources->data; | |
4450 | 3368 char *status; |
3311 | 3369 realwho = g_strdup_printf("%s/%s", buddy, jri->name); |
4450 | 3370 status = strdup_withhtml(jabber_lookup_away(gjc, realwho)); |
5236 | 3371 *ap++ = g_strdup_printf("<B>%s:</B> %s<BR>\n", _("Jabber ID"), realwho); |
3372 *ap++ = g_strdup_printf("<B>%s:</B> %s%s%s<BR>\n", _("Status"), jabber_get_state_string(jri->state), status ? ": " : "", status ? status : ""); | |
4450 | 3373 g_free(status); |
3311 | 3374 g_free(realwho); |
3375 resources = resources->next; | |
2956 | 3376 } |
3377 | |
3378 *ap = NULL; | |
3770 | 3379 |
3311 | 3380 g_free(buddy); |
2956 | 3381 |
3382 final= g_strjoinv(NULL, str_arr); | |
3383 g_strfreev(str_arr); | |
3384 | |
3311 | 3385 g_show_info_text(gc, who, 2, final, NULL); |
2956 | 3386 g_free(final); |
3770 | 3387 |
2956 | 3388 } |
3389 | |
6059 | 3390 static void jabber_get_cb_info(GaimConnection *gc, int cid, const char *who) { |
2956 | 3391 struct jabber_chat *jc = NULL; |
3392 char *realwho; | |
3393 | |
3394 /* Find out which chat */ | |
3395 if(jabber_find_chat_by_convo_id(gc, cid, &jc) != 0) | |
3396 return; | |
3397 | |
3311 | 3398 realwho = g_strdup_printf("%s@%s/%s", jc->gjid->user, jc->gjid->server, who); |
2956 | 3399 |
3400 jabber_get_info(gc, realwho); | |
3401 g_free(realwho); | |
3402 } | |
3403 | |
6059 | 3404 static void jabber_get_cb_away_msg(GaimConnection *gc, int cid, const char *who) { |
2956 | 3405 struct jabber_chat *jc = NULL; |
3406 char *realwho; | |
3407 | |
3408 /* Find out which chat */ | |
3409 if(jabber_find_chat_by_convo_id(gc, cid, &jc) != 0) | |
3410 return; | |
3411 | |
3311 | 3412 realwho = g_strdup_printf("%s@%s/%s", jc->gjid->user, jc->gjid->server, who); |
2956 | 3413 |
3414 jabber_get_away_msg(gc, realwho); | |
3415 g_free(realwho); | |
3416 | |
3417 } | |
3418 | |
6695 | 3419 static char *jabber_tooltip_text(GaimBuddy *b) |
4744 | 3420 { |
5135 | 3421 struct jabber_buddy_data *jbd = jabber_find_buddy(b->account->gc, b->name, FALSE); |
4745 | 3422 jab_res_info jri = jabber_find_resource(b->account->gc, b->name); |
5135 | 3423 char *ret = NULL; |
4745 | 3424 if(jri) { |
4777 | 3425 char *stripped = strip_html(jabber_lookup_away(GC_GJ(b->account->gc), |
4745 | 3426 b->name)); |
4777 | 3427 char *text = NULL; |
3428 if(stripped) | |
3429 text = g_markup_escape_text(stripped, strlen(stripped)); | |
5236 | 3430 ret = g_strdup_printf("<b>%s:</b> %s%s%s", |
3431 _("Status"), | |
4745 | 3432 jabber_get_state_string(jri->state), text ? ": " : "", |
3433 text ? text : ""); | |
3434 | |
4777 | 3435 if(stripped) { |
3436 g_free(stripped); | |
4745 | 3437 g_free(text); |
4777 | 3438 } |
5136 | 3439 } else if(jbd && !GAIM_BUDDY_IS_ONLINE(b) && |
3440 (jbd->subscription & JABBER_SUB_PENDING || | |
5135 | 3441 !(jbd->subscription & JABBER_SUB_TO))) { |
5236 | 3442 ret = g_strdup_printf("<b>%s:</b> %s", _("Status"), _("Not Authorized")); |
4745 | 3443 } |
5135 | 3444 return ret; |
4744 | 3445 } |
3446 | |
6695 | 3447 static char *jabber_status_text(GaimBuddy *b) |
4732 | 3448 { |
5135 | 3449 struct jabber_buddy_data *jbd = jabber_find_buddy(b->account->gc, b->name, FALSE); |
3450 char *ret = NULL; | |
4732 | 3451 if (b->uc & UC_UNAVAILABLE) { |
4777 | 3452 char *stripped = strip_html(jabber_lookup_away(GC_GJ(b->account->gc), |
4745 | 3453 b->name)); |
4777 | 3454 if(!stripped) { |
4745 | 3455 jab_res_info jri = jabber_find_resource(b->account->gc, b->name); |
3456 if(jri) | |
4777 | 3457 stripped = g_strdup(jabber_get_state_string(jri->state)); |
4745 | 3458 } |
4777 | 3459 ret = g_markup_escape_text(stripped, strlen(stripped)); |
3460 g_free(stripped); | |
5136 | 3461 } else if(jbd && !GAIM_BUDDY_IS_ONLINE(b) && |
3462 (jbd->subscription & JABBER_SUB_PENDING || | |
5135 | 3463 !(jbd->subscription & JABBER_SUB_TO))) { |
3464 ret = g_strdup(_("Not Authorized")); | |
4732 | 3465 } |
5135 | 3466 return ret; |
4732 | 3467 } |
3468 | |
6806 | 3469 static void jabber_rereq_auth(GaimConnection *gc, const char *who) { |
3470 jabber_add_buddy(gc, who, NULL); | |
3471 } | |
3472 | |
5572 | 3473 static GList *jabber_buddy_menu(GaimConnection *gc, const char *who) { |
2170
c24595d3c364
[gaim-migrate @ 2180]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2167
diff
changeset
|
3474 GList *m = NULL; |
c24595d3c364
[gaim-migrate @ 2180]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2167
diff
changeset
|
3475 struct proto_buddy_menu *pbm; |
6695 | 3476 GaimBuddy *b = gaim_find_buddy(gc->account, who); |
3311 | 3477 |
3478 if(b->uc == UC_ERROR) | |
3479 { | |
3480 pbm = g_new0(struct proto_buddy_menu, 1); | |
3481 pbm->label = _("View Error Msg"); | |
3482 pbm->callback = jabber_get_error_msg; | |
3483 pbm->gc = gc; | |
3484 m = g_list_append(m, pbm); | |
3485 } else { | |
3340 | 3486 gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc; |
3487 char *realwho = get_realwho(gjc, who, FALSE, NULL); | |
5135 | 3488 struct jabber_buddy_data *jbd = jabber_find_buddy(gc, realwho, FALSE); |
3340 | 3489 |
3490 g_free(realwho); | |
3491 | |
3311 | 3492 pbm = g_new0(struct proto_buddy_menu, 1); |
3493 pbm->label = _("Get Away Msg"); | |
3494 pbm->callback = jabber_get_away_msg; | |
3495 pbm->gc = gc; | |
3496 m = g_list_append(m, pbm); | |
3340 | 3497 |
3498 pbm = g_new0(struct proto_buddy_menu, 1); | |
3499 if(jbd && (jbd->invisible & JABBER_BUD_INVIS)) { | |
3500 pbm->label = _("Un-hide From"); | |
3501 pbm->callback = jabber_visible_to_buddy; | |
3502 } else { | |
3503 pbm->label = _("Temporarily Hide From"); | |
3504 pbm->callback = jabber_invisible_to_buddy; | |
3505 } | |
4916 | 3506 |
3507 pbm->gc = gc; | |
3508 m = g_list_append(m, pbm); | |
3509 pbm = g_new0(struct proto_buddy_menu, 1); | |
3510 pbm->label = _("Cancel Presence Notification"); | |
3511 pbm->callback = jabber_unsubscribe_buddy_from_us; | |
3340 | 3512 pbm->gc = gc; |
3513 m = g_list_append(m, pbm); | |
5136 | 3514 |
3515 if(jbd && !GAIM_BUDDY_IS_ONLINE(b) && | |
3516 !(jbd->subscription & JABBER_SUB_TO)) { | |
3517 pbm = g_new0(struct proto_buddy_menu, 1); | |
3518 pbm->label = _("Re-request authorization"); | |
6806 | 3519 pbm->callback = jabber_rereq_auth; |
5136 | 3520 pbm->gc = gc; |
3521 m = g_list_append(m, pbm); | |
3522 } | |
3311 | 3523 } |
2170
c24595d3c364
[gaim-migrate @ 2180]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2167
diff
changeset
|
3524 |
c24595d3c364
[gaim-migrate @ 2180]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2167
diff
changeset
|
3525 return m; |
2086 | 3526 } |
3527 | |
5572 | 3528 static GList *jabber_away_states(GaimConnection *gc) { |
2086 | 3529 GList *m = NULL; |
3530 | |
4982 | 3531 m = g_list_append(m, _("Online")); |
3532 m = g_list_append(m, _("Chatty")); | |
3533 m = g_list_append(m, _("Away")); | |
3534 m = g_list_append(m, _("Extended Away")); | |
3535 m = g_list_append(m, _("Do Not Disturb")); | |
3536 m = g_list_append(m, _("Invisible")); | |
4110 | 3537 m = g_list_append(m, GAIM_AWAY_CUSTOM); |
2086 | 3538 |
3539 return m; | |
3540 } | |
3541 | |
6059 | 3542 static void jabber_set_away(GaimConnection *gc, const char *state, const char *message) |
2086 | 3543 { |
3544 xmlnode x, y; | |
3545 struct jabber_data *jd = gc->proto_data; | |
2956 | 3546 gjconn gjc = jd->gjc; |
3311 | 3547 GSList *jcs; |
3548 struct jabber_chat *jc; | |
3549 char *chatname; | |
3340 | 3550 gboolean invisible = FALSE; |
2086 | 3551 |
4111
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3552 if (gc->away) { |
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3553 g_free(gc->away); |
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3554 gc->away = NULL; |
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3555 } |
2086 | 3556 |
3557 x = xmlnode_new_tag("presence"); | |
3558 | |
3559 if (!strcmp(state, GAIM_AWAY_CUSTOM)) { | |
3560 /* oh goody. Gaim is telling us what to do. */ | |
3561 if (message) { | |
3562 /* Gaim wants us to be away */ | |
5174 | 3563 char *stripped; |
3564 | |
3565 /* Jabber supports XHTML in IMs, but not in away messages. */ | |
3566 html_to_xhtml(message, NULL, &stripped); | |
3567 | |
2086 | 3568 y = xmlnode_insert_tag(x, "show"); |
3569 xmlnode_insert_cdata(y, "away", -1); | |
3570 y = xmlnode_insert_tag(x, "status"); | |
5174 | 3571 xmlnode_insert_cdata(y, stripped, -1); |
3572 | |
3573 gc->away = g_strdup(stripped); | |
3574 g_free(stripped); | |
2086 | 3575 } else { |
3576 /* Gaim wants us to not be away */ | |
3577 /* but for Jabber, we can just send presence with no other information. */ | |
3578 } | |
3579 } else { | |
3580 /* state is one of our own strings. it won't be NULL. */ | |
4982 | 3581 if (!strcmp(state, _("Online"))) { |
2086 | 3582 /* once again, we don't have to put anything here */ |
4982 | 3583 } else if (!strcmp(state, _("Chatty"))) { |
2086 | 3584 y = xmlnode_insert_tag(x, "show"); |
3585 xmlnode_insert_cdata(y, "chat", -1); | |
4111
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3586 gc->away = g_strdup(""); |
4982 | 3587 } else if (!strcmp(state, _("Away"))) { |
2086 | 3588 y = xmlnode_insert_tag(x, "show"); |
3589 xmlnode_insert_cdata(y, "away", -1); | |
4111
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3590 gc->away = g_strdup(""); |
4982 | 3591 } else if (!strcmp(state, _("Extended Away"))) { |
2086 | 3592 y = xmlnode_insert_tag(x, "show"); |
3593 xmlnode_insert_cdata(y, "xa", -1); | |
4111
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3594 gc->away = g_strdup(""); |
4982 | 3595 } else if (!strcmp(state, _("Do Not Disturb"))) { |
2086 | 3596 y = xmlnode_insert_tag(x, "show"); |
3597 xmlnode_insert_cdata(y, "dnd", -1); | |
4111
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3598 gc->away = g_strdup(""); |
4982 | 3599 } else if (!strcmp(state, _("Invisible"))) { |
3340 | 3600 xmlnode_put_attrib(x, "type", "invisible"); |
4111
ee884f1d7ae3
[gaim-migrate @ 4326]
Christian Hammond <chipx86@chipx86.com>
parents:
4110
diff
changeset
|
3601 gc->away = g_strdup(""); |
3340 | 3602 invisible = TRUE; |
2086 | 3603 } |
3604 } | |
3605 | |
3311 | 3606 gjab_send(gjc, x); /* Notify "individuals" */ |
3607 | |
3608 /* | |
3609 * As of jabberd-1.4.2: simply sending presence to the server doesn't result in | |
3610 * it being propagated to conference rooms. So we wade thru the list of chats, | |
3611 * sending our new presence status to each and every one. | |
3612 */ | |
3613 for(jcs = jd->chats; jcs; jcs = jcs->next) { | |
3614 jc = jcs->data; | |
3615 if(jc->state == JCS_ACTIVE) { | |
3616 xmlnode_put_attrib(x, "from", jc->gjid->full); | |
3617 chatname = g_strdup_printf("%s@%s", jc->gjid->user, jc->gjid->server); | |
3618 xmlnode_put_attrib(x, "to", chatname); | |
3619 gjab_send(gjc, x); | |
3620 g_free(chatname); | |
3621 } | |
3622 } | |
3623 | |
2086 | 3624 xmlnode_free(x); |
3340 | 3625 |
3626 invisible_to_all_buddies(gc, invisible); | |
2086 | 3627 } |
3628 | |
5572 | 3629 static void jabber_set_idle(GaimConnection *gc, int idle) { |
2086 | 3630 struct jabber_data *jd = (struct jabber_data *)gc->proto_data; |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
3631 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
3632 "jabber_set_idle: setting idle %i\n", idle); |
3770 | 3633 jd->idle = idle ? time(NULL) - idle : idle; |
2086 | 3634 } |
3635 | |
5572 | 3636 static void jabber_keepalive(GaimConnection *gc) { |
2086 | 3637 struct jabber_data *jd = (struct jabber_data *)gc->proto_data; |
4450 | 3638 gjab_send_raw(jd->gjc, JABBER_KEEPALIVE_STRING); |
2086 | 3639 } |
3640 | |
2956 | 3641 /*---------------------------------------*/ |
3642 /* Jabber "set info" (vCard) support */ | |
3643 /*---------------------------------------*/ | |
3644 | |
3645 /* | |
3646 * V-Card format: | |
3647 * | |
3648 * <vCard prodid='' version='' xmlns=''> | |
3649 * <FN></FN> | |
3650 * <N> | |
3651 * <FAMILY/> | |
3652 * <GIVEN/> | |
3653 * </N> | |
3654 * <NICKNAME/> | |
3655 * <URL/> | |
3656 * <ADR> | |
3657 * <STREET/> | |
3658 * <EXTADD/> | |
3659 * <LOCALITY/> | |
3660 * <REGION/> | |
3661 * <PCODE/> | |
3662 * <COUNTRY/> | |
3663 * </ADR> | |
3664 * <TEL/> | |
3665 * <EMAIL/> | |
3666 * <ORG> | |
3667 * <ORGNAME/> | |
3668 * <ORGUNIT/> | |
3669 * </ORG> | |
3670 * <TITLE/> | |
3671 * <ROLE/> | |
3672 * <DESC/> | |
3673 * <BDAY/> | |
3674 * </vCard> | |
3675 * | |
3676 * See also: | |
3677 * | |
3678 * http://docs.jabber.org/proto/html/vcard-temp.html | |
3679 * http://www.vcard-xml.org/dtd/vCard-XML-v2-20010520.dtd | |
3680 */ | |
3681 | |
3682 /* | |
3683 * Cross-reference user-friendly V-Card entry labels to vCard XML tags | |
3684 * and attributes. | |
3685 * | |
3686 * Order is (or should be) unimportant. For example: we have no way of | |
3687 * knowing in what order real data will arrive. | |
3688 * | |
3689 * Format: Label, Pre-set text, "visible" flag, "editable" flag, XML tag | |
3690 * name, XML tag's parent tag "path" (relative to vCard node). | |
3691 * | |
3692 * List is terminated by a NULL label pointer. | |
3693 * | |
3694 * Entries with no label text, but with XML tag and parent tag | |
3695 * entries, are used by V-Card XML construction routines to | |
3696 * "automagically" construct the appropriate XML node tree. | |
3697 * | |
3698 * Thoughts on future direction/expansion | |
3699 * | |
3700 * This is a "simple" vCard. | |
3701 * | |
3702 * It is possible for nodes other than the "vCard" node to have | |
3703 * attributes. Should that prove necessary/desirable, add an | |
3704 * "attributes" pointer to the vcard_template struct, create the | |
3705 * necessary tag_attr structs, and add 'em to the vcard_dflt_data | |
3706 * array. | |
3707 * | |
3708 * The above changes will (obviously) require changes to the vCard | |
3709 * construction routines. | |
3710 */ | |
3711 | |
3712 struct vcard_template { | |
3713 char *label; /* label text pointer */ | |
3714 char *text; /* entry text pointer */ | |
3715 int visible; /* should entry field be "visible?" */ | |
3716 int editable; /* should entry field be editable? */ | |
3717 char *tag; /* tag text */ | |
3718 char *ptag; /* parent tag "path" text */ | |
3719 char *url; /* vCard display format if URL */ | |
3720 } vcard_template_data[] = { | |
2975 | 3721 {N_("Full Name"), NULL, TRUE, TRUE, "FN", NULL, NULL}, |
3722 {N_("Family Name"), NULL, TRUE, TRUE, "FAMILY", "N", NULL}, | |
3723 {N_("Given Name"), NULL, TRUE, TRUE, "GIVEN", "N", NULL}, | |
3724 {N_("Nickname"), NULL, TRUE, TRUE, "NICKNAME", NULL, NULL}, | |
3725 {N_("URL"), NULL, TRUE, TRUE, "URL", NULL, "<A HREF=\"%s\">%s</A>"}, | |
3726 {N_("Street Address"), NULL, TRUE, TRUE, "STREET", "ADR", NULL}, | |
3727 {N_("Extended Address"), NULL, TRUE, TRUE, "EXTADD", "ADR", NULL}, | |
3728 {N_("Locality"), NULL, TRUE, TRUE, "LOCALITY", "ADR", NULL}, | |
3729 {N_("Region"), NULL, TRUE, TRUE, "REGION", "ADR", NULL}, | |
3730 {N_("Postal Code"), NULL, TRUE, TRUE, "PCODE", "ADR", NULL}, | |
3731 {N_("Country"), NULL, TRUE, TRUE, "COUNTRY", "ADR", NULL}, | |
3732 {N_("Telephone"), NULL, TRUE, TRUE, "TELEPHONE", NULL, NULL}, | |
3733 {N_("Email"), NULL, TRUE, TRUE, "EMAIL", NULL, "<A HREF=\"mailto:%s\">%s</A>"}, | |
3734 {N_("Organization Name"), NULL, TRUE, TRUE, "ORGNAME", "ORG", NULL}, | |
3735 {N_("Organization Unit"), NULL, TRUE, TRUE, "ORGUNIT", "ORG", NULL}, | |
3736 {N_("Title"), NULL, TRUE, TRUE, "TITLE", NULL, NULL}, | |
3737 {N_("Role"), NULL, TRUE, TRUE, "ROLE", NULL, NULL}, | |
3738 {N_("Birthday"), NULL, TRUE, TRUE, "BDAY", NULL, NULL}, | |
3739 {N_("Description"), NULL, TRUE, TRUE, "DESC", NULL, NULL}, | |
2956 | 3740 {"", NULL, TRUE, TRUE, "N", NULL, NULL}, |
3741 {"", NULL, TRUE, TRUE, "ADR", NULL, NULL}, | |
3742 {"", NULL, TRUE, TRUE, "ORG", NULL, NULL}, | |
3743 {NULL, NULL, 0, 0, NULL, NULL, NULL} | |
3744 }; | |
3745 | |
3746 /* | |
3747 * The "vCard" tag's attibute list... | |
3748 */ | |
3749 struct tag_attr { | |
3750 char *attr; | |
3751 char *value; | |
3752 } vcard_tag_attr_list[] = { | |
3753 {"prodid", "-//HandGen//NONSGML vGen v1.0//EN"}, | |
3754 {"version", "2.0", }, | |
3755 {"xmlns", "vcard-temp", }, | |
3756 {NULL, NULL}, | |
3757 }; | |
3758 | |
3759 | |
3760 /* | |
3761 * Used by routines to parse an XML-encoded string into an xmlnode tree | |
3762 */ | |
3763 typedef struct { | |
3764 XML_Parser parser; | |
3765 xmlnode current; | |
3766 } *xmlstr2xmlnode_parser, xmlstr2xmlnode_parser_struct; | |
3767 | |
3768 | |
3769 /* | |
3770 * Display a Jabber vCard | |
3771 */ | |
3772 static void jabber_handlevcard(gjconn gjc, xmlnode querynode, char *from) | |
3773 { | |
5572 | 3774 GaimConnection *gc = GJ_GC(gjc); |
2956 | 3775 char *cdata, *status; |
3776 struct vcard_template *vc_tp = vcard_template_data; | |
3777 | |
3778 /* space for all vCard elements + Jabber I.D. + "status" + NULL (list terminator) */ | |
3779 gchar **str_arr = (gchar **) g_new(gpointer, | |
3780 (sizeof(vcard_template_data)/sizeof(struct vcard_template)) + 3); | |
3781 gchar **ap = str_arr; | |
3782 gchar *buddy, *final; | |
3783 | |
4745 | 3784 jab_res_info jri; |
3785 | |
3311 | 3786 if((buddy = get_realwho(gjc, from, TRUE, NULL)) == NULL) { |
3787 g_strfreev(str_arr); | |
3788 return; | |
2956 | 3789 } |
3311 | 3790 |
4745 | 3791 jri = jabber_find_resource(GJ_GC(gjc), buddy); |
3792 | |
5236 | 3793 *ap++ = g_strdup_printf("<B>%s:</B> %s<BR>\n", _("Jabber ID"), buddy); |
2956 | 3794 |
3795 for(vc_tp = vcard_template_data; vc_tp->label != NULL; ++vc_tp) { | |
3796 if(strcmp(vc_tp->tag, "DESC") == 0) | |
3797 continue; /* special handling later */ | |
3798 if(vc_tp->ptag == NULL) { | |
3799 cdata = xmlnode_get_tag_data(querynode, vc_tp->tag); | |
3800 } else { | |
3801 gchar *tag = g_strdup_printf("%s/%s", vc_tp->ptag, vc_tp->tag); | |
3802 cdata = xmlnode_get_tag_data(querynode, tag); | |
3803 g_free(tag); | |
3804 } | |
3805 if(cdata != NULL) { | |
3806 if(vc_tp->url == NULL) { | |
5236 | 3807 *ap++ = g_strdup_printf("<B>%s:</B> %s<BR>\n", _(vc_tp->label), cdata); |
2956 | 3808 } else { |
3809 gchar *fmt = g_strdup_printf("<B>%%s:</B> %s<BR>\n", vc_tp->url); | |
5236 | 3810 *ap++ = g_strdup_printf(fmt, _(vc_tp->label), cdata, cdata); |
2956 | 3811 g_free(fmt); |
3812 } | |
3813 } | |
3814 } | |
3815 | |
4745 | 3816 |
4450 | 3817 status = strdup_withhtml(jabber_lookup_away(gjc, buddy)); |
5236 | 3818 *ap++ = g_strdup_printf("<B>%s:</B> %s%s%s<BR>\n", |
3819 _("Status"), | |
4745 | 3820 jri ? jabber_get_state_string(jri->state) : "", |
3821 jri && status ? ": " : "", status ? status : ""); | |
4450 | 3822 g_free(status); |
2956 | 3823 |
3824 /* | |
3825 * "Description" handled as a special case: get a copy of the | |
3826 * string and HTML-ize. | |
3827 */ | |
3828 if((cdata = xmlnode_get_tag_data(querynode, "DESC")) != NULL) { | |
3829 gchar *tmp = g_strdup_printf("<HR>%s<BR>", cdata); | |
3830 *ap++ = strdup_withhtml(tmp); | |
3831 g_free(tmp); | |
3832 } | |
3833 | |
3834 *ap = NULL; | |
3835 | |
3836 final= g_strjoinv(NULL, str_arr); | |
3837 g_strfreev(str_arr); | |
3838 | |
3839 g_show_info_text(gc, buddy, 2, final, NULL); | |
3840 g_free(buddy); | |
3841 g_free(final); | |
3842 } | |
3843 | |
3844 /* | |
3845 * Used by XML_Parse on parsing CDATA | |
3846 */ | |
3847 static void xmlstr2xmlnode_charData(void *userdata, const char *s, int slen) | |
3848 { | |
3849 xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; | |
3850 | |
3851 if (xmlp->current) | |
3852 xmlnode_insert_cdata(xmlp->current, s, slen); | |
3853 } | |
3854 | |
3855 /* | |
3856 * Used by XML_Parse to start or append to an xmlnode | |
3857 */ | |
3858 static void xmlstr2xmlnode_startElement(void *userdata, const char *name, const char **attribs) | |
3859 { | |
3860 xmlnode x; | |
3861 xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; | |
3862 | |
3863 if (xmlp->current) { | |
3864 /* Append the node to the current one */ | |
3865 x = xmlnode_insert_tag(xmlp->current, name); | |
3866 xmlnode_put_expat_attribs(x, attribs); | |
3867 | |
3868 xmlp->current = x; | |
3869 } else { | |
3870 x = xmlnode_new_tag(name); | |
3871 xmlnode_put_expat_attribs(x, attribs); | |
3872 xmlp->current = x; | |
3873 } | |
3874 } | |
3875 | |
3876 /* | |
3877 * Used by XML_Parse to end an xmlnode | |
3878 */ | |
3879 static void xmlstr2xmlnode_endElement(void *userdata, const char *name) | |
3880 { | |
3881 xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata; | |
3882 xmlnode x; | |
3883 | |
3884 if (xmlp->current != NULL && (x = xmlnode_get_parent(xmlp->current)) != NULL) { | |
3885 xmlp->current = x; | |
3886 } | |
3887 } | |
3888 | |
3889 /* | |
3890 * Parse an XML-encoded string into an xmlnode tree | |
3891 * | |
3892 * Caller is responsible for freeing the returned xmlnode | |
3893 */ | |
3894 static xmlnode xmlstr2xmlnode(char *xmlstring) | |
3895 { | |
3896 xmlstr2xmlnode_parser my_parser = g_new(xmlstr2xmlnode_parser_struct, 1); | |
3897 xmlnode x = NULL; | |
3898 | |
3899 my_parser->parser = XML_ParserCreate(NULL); | |
3900 my_parser->current = NULL; | |
3901 | |
3902 XML_SetUserData(my_parser->parser, (void *)my_parser); | |
3903 XML_SetElementHandler(my_parser->parser, xmlstr2xmlnode_startElement, xmlstr2xmlnode_endElement); | |
3904 XML_SetCharacterDataHandler(my_parser->parser, xmlstr2xmlnode_charData); | |
3905 XML_Parse(my_parser->parser, xmlstring, strlen(xmlstring), 0); | |
3906 | |
3907 x = my_parser->current; | |
3908 | |
3909 XML_ParserFree(my_parser->parser); | |
3910 g_free(my_parser); | |
3911 | |
3912 return(x); | |
3913 } | |
3914 | |
3915 /* | |
3916 * Insert a tag node into an xmlnode tree, recursively inserting parent tag | |
3917 * nodes as necessary | |
3918 * | |
3919 * Returns pointer to inserted node | |
3920 * | |
3921 * Note to hackers: this code is designed to be re-entrant (it's recursive--it | |
3922 * calls itself), so don't put any "static"s in here! | |
3923 */ | |
3924 static xmlnode insert_tag_to_parent_tag(xmlnode start, const char *parent_tag, const char *new_tag) | |
3925 { | |
3926 xmlnode x = NULL; | |
3927 | |
3928 /* | |
3929 * If the parent tag wasn't specified, see if we can get it | |
3930 * from the vCard template struct. | |
3931 */ | |
3932 if(parent_tag == NULL) { | |
3933 struct vcard_template *vc_tp = vcard_template_data; | |
3934 | |
3935 while(vc_tp->label != NULL) { | |
3936 if(strcmp(vc_tp->tag, new_tag) == 0) { | |
3937 parent_tag = vc_tp->ptag; | |
3938 break; | |
3939 } | |
3940 ++vc_tp; | |
3941 } | |
3942 } | |
3943 | |
3944 /* | |
3945 * If we have a parent tag... | |
3946 */ | |
3947 if(parent_tag != NULL ) { | |
3948 /* | |
3949 * Try to get the parent node for a tag | |
3950 */ | |
3951 if((x = xmlnode_get_tag(start, parent_tag)) == NULL) { | |
3952 /* | |
3953 * Descend? | |
3954 */ | |
3955 char *grand_parent = strcpy(g_malloc(strlen(parent_tag) + 1), parent_tag); | |
3956 char *parent; | |
3957 | |
3958 if((parent = strrchr(grand_parent, '/')) != NULL) { | |
3959 *(parent++) = '\0'; | |
3960 x = insert_tag_to_parent_tag(start, grand_parent, parent); | |
3961 } else { | |
3962 x = xmlnode_insert_tag(start, grand_parent); | |
3963 } | |
3964 g_free(grand_parent); | |
3965 } else { | |
3966 /* | |
3967 * We found *something* to be the parent node. | |
3968 * Note: may be the "root" node! | |
3969 */ | |
3970 xmlnode y; | |
3971 if((y = xmlnode_get_tag(x, new_tag)) != NULL) { | |
3972 return(y); | |
3973 } | |
3974 } | |
3975 } | |
3976 | |
3977 /* | |
3978 * insert the new tag into its parent node | |
3979 */ | |
3980 return(xmlnode_insert_tag((x == NULL? start : x), new_tag)); | |
3981 } | |
3982 | |
3983 /* | |
3984 * Send vCard info to Jabber server | |
3985 */ | |
5954 | 3986 static void jabber_set_info(GaimConnection *gc, const char *info) |
2956 | 3987 { |
3988 xmlnode x, vc_node; | |
3989 char *id; | |
3990 struct jabber_data *jd = gc->proto_data; | |
3991 gjconn gjc = jd->gjc; | |
5954 | 3992 gchar *info2; |
2956 | 3993 |
3994 x = xmlnode_new_tag("iq"); | |
3311 | 3995 xmlnode_put_attrib(x, "type", "set"); |
2956 | 3996 |
3997 id = gjab_getid(gjc); | |
3770 | 3998 |
2956 | 3999 xmlnode_put_attrib(x, "id", id); |
4000 | |
4001 /* | |
4002 * Send only if there's actually any *information* to send | |
4003 */ | |
5954 | 4004 info2 = g_strdup(info); |
4005 vc_node = xmlstr2xmlnode(info2); | |
4874 | 4006 |
4007 if(vc_node) { | |
4008 if (xmlnode_get_name(vc_node) && | |
4009 !g_ascii_strncasecmp(xmlnode_get_name(vc_node), "vcard", 5)) { | |
4010 xmlnode_insert_tag_node(x, vc_node); | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
4011 gaim_debug(GAIM_DEBUG_MISC, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
4012 "jabber: vCard packet: %s\n", xmlnode2str(x)); |
4874 | 4013 gjab_send(gjc, x); |
4014 } | |
4015 xmlnode_free(vc_node); | |
2956 | 4016 } |
4017 | |
4018 xmlnode_free(x); | |
5954 | 4019 g_free(info2); |
2956 | 4020 } |
4021 | |
4022 /* | |
4023 * This is the callback from the "ok clicked" for "set vCard" | |
4024 * | |
4025 * Formats GSList data into XML-encoded string and returns a pointer | |
4026 * to said string. | |
4027 * | |
4028 * g_free()'ing the returned string space is the responsibility of | |
4029 * the caller. | |
4030 */ | |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4031 static void |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4032 jabber_format_info(GaimConnection *gc, GaimRequestFields *fields) |
2956 | 4033 { |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4034 GaimAccount *account; |
2956 | 4035 xmlnode vc_node; |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4036 GaimRequestField *field; |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4037 const char *text; |
2956 | 4038 char *p; |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4039 const struct vcard_template *vc_tp; |
2956 | 4040 struct tag_attr *tag_attr; |
4041 | |
4042 vc_node = xmlnode_new_tag("vCard"); | |
4043 | |
4044 for(tag_attr = vcard_tag_attr_list; tag_attr->attr != NULL; ++tag_attr) | |
4045 xmlnode_put_attrib(vc_node, tag_attr->attr, tag_attr->value); | |
4046 | |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4047 for (vc_tp = vcard_template_data; vc_tp->label != NULL; vc_tp++) { |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4048 if (*vc_tp->label == '\0') |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4049 continue; |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4050 |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4051 field = gaim_request_fields_get_field(fields, vc_tp->tag); |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4052 text = gaim_request_field_string_get_value(field); |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4053 |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4054 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4055 "Setting %s to '%s'\n", vc_tp->tag, text); |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4056 |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4057 if (text != NULL && *text != '\0') { |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4058 xmlnode xp; |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4059 |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4060 if ((xp = insert_tag_to_parent_tag(vc_node, |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4061 NULL, vc_tp->tag)) != NULL) { |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4062 |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4063 xmlnode_insert_cdata(xp, text, -1); |
2956 | 4064 } |
4065 } | |
4066 } | |
4067 | |
4068 p = g_strdup(xmlnode2str(vc_node)); | |
4069 xmlnode_free(vc_node); | |
4070 | |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4071 account = gaim_connection_get_account(gc); |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4072 |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4073 if (account != NULL) { |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4074 gaim_account_set_user_info(account, p); |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4075 |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4076 if (gc != NULL) |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4077 serv_set_info(gc, p); |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4078 } |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4079 |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4080 g_free(p); |
2956 | 4081 } |
4082 | |
4083 /* | |
4084 * This gets executed by the proto action | |
4085 * | |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4086 * Creates a new GaimRequestFields struct, gets the XML-formatted user_info |
2956 | 4087 * string (if any) into GSLists for the (multi-entry) edit dialog and |
4088 * calls the set_vcard dialog. | |
4089 */ | |
5572 | 4090 static void jabber_setup_set_info(GaimConnection *gc) |
2956 | 4091 { |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4092 GaimRequestFields *fields; |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4093 GaimRequestFieldGroup *group; |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4094 GaimRequestField *field; |
2956 | 4095 const struct vcard_template *vc_tp; |
4096 char *user_info; | |
4097 char *cdata; | |
4098 xmlnode x_vc_data = NULL; | |
6294 | 4099 |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4100 fields = gaim_request_fields_new(); |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4101 group = gaim_request_field_group_new(NULL); |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4102 gaim_request_fields_add_group(fields, group); |
2956 | 4103 |
4104 /* | |
4105 * Get existing, XML-formatted, user info | |
4106 */ | |
6294 | 4107 if((user_info = g_strdup(gaim_account_get_user_info(gc->account))) != NULL) |
2956 | 4108 x_vc_data = xmlstr2xmlnode(user_info); |
6294 | 4109 else |
4110 user_info = g_strdup(""); | |
2956 | 4111 |
4112 /* | |
4113 * Set up GSLists for edit with labels from "template," data from user info | |
4114 */ | |
4115 for(vc_tp = vcard_template_data; vc_tp->label != NULL; ++vc_tp) { | |
4116 if((vc_tp->label)[0] == '\0') | |
4117 continue; | |
4118 if(vc_tp->ptag == NULL) { | |
4119 cdata = xmlnode_get_tag_data(x_vc_data, vc_tp->tag); | |
4120 } else { | |
4121 gchar *tag = g_strdup_printf("%s/%s", vc_tp->ptag, vc_tp->tag); | |
4122 cdata = xmlnode_get_tag_data(x_vc_data, tag); | |
4123 g_free(tag); | |
4124 } | |
4125 if(strcmp(vc_tp->tag, "DESC") == 0) { | |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4126 field = gaim_request_field_string_new(vc_tp->tag, |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4127 _(vc_tp->label), cdata, |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4128 TRUE); |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4129 #if 0 |
2956 | 4130 multi_text_list_update(&(b->multi_text_items), |
4131 vc_tp->label, cdata, TRUE); | |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4132 #endif |
2956 | 4133 } else { |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4134 field = gaim_request_field_string_new(vc_tp->tag, |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4135 _(vc_tp->label), cdata, |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4136 FALSE); |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4137 #if 0 |
2956 | 4138 data = multi_entry_list_update(&(b->multi_entry_items), |
4139 vc_tp->label, cdata, TRUE); | |
4140 data->visible = vc_tp->visible; | |
4141 data->editable = vc_tp->editable; | |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4142 #endif |
2956 | 4143 } |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4144 |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4145 gaim_request_field_group_add_field(group, field); |
2956 | 4146 } |
4147 | |
4148 if(x_vc_data != NULL) { | |
4149 xmlnode_free(x_vc_data); | |
4150 } else { | |
4151 /* | |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4152 * I'm commenting this out for now. faceprint can look at it |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4153 * later. The comment below says this is going away "real soon now," |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4154 * but it's probably been here a really long time. Getting this |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4155 * to work with the multi-field stuff won't be pretty, since we're |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4156 * manually going to have to search through all fields for the |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4157 * label and update. |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4158 * |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4159 * -- ChipX86 |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4160 */ |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4161 #if 0 |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4162 /* |
2956 | 4163 * Early Beta versions had a different user_info storage format--let's |
4164 * see if that works. | |
4165 * | |
4166 * This goes away RSN. | |
4167 */ | |
4168 const char *record_separator = "<BR>"; | |
4169 const char *field_separator = ": "; | |
4170 gchar **str_list, **str_list_ptr, **str_list2; | |
4171 | |
4172 if((str_list = g_strsplit(user_info, record_separator, 0)) != NULL) { | |
4173 for(str_list_ptr = str_list; *str_list_ptr != NULL; ++str_list_ptr) { | |
4174 str_list2 = g_strsplit(*str_list_ptr, field_separator, 2); | |
4175 if(str_list2[0] != NULL && str_list2[1] != NULL) { | |
4176 g_strstrip(str_list2[0]); | |
4177 g_strstrip(str_list2[1]); | |
4178 /* this is ugly--so far */ | |
4179 if(strcmp(str_list2[0], "Description") == 0) { | |
4180 multi_text_list_update(&(b->multi_text_items), | |
4181 str_list2[0], str_list2[1], FALSE); | |
4182 } else { | |
4183 multi_entry_list_update(&(b->multi_entry_items), | |
4184 str_list2[0], str_list2[1], FALSE); | |
4185 } | |
4186 } | |
4187 g_strfreev(str_list2); | |
4188 } | |
4189 g_strfreev(str_list); | |
4190 } | |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4191 #endif |
2956 | 4192 } |
4193 | |
6294 | 4194 g_free(user_info); |
2956 | 4195 |
6339
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4196 gaim_request_fields(gc, _("Edit Jabber vCard"), |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4197 _("Edit Jabber vCard"), |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4198 _("All items below are optional. Enter only the " |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4199 "information with which you feel comfortable."), |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4200 fields, |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4201 _("Save"), G_CALLBACK(jabber_format_info), |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4202 _("Cancel"), NULL, |
cc527f9ba197
[gaim-migrate @ 6838]
Christian Hammond <chipx86@chipx86.com>
parents:
6321
diff
changeset
|
4203 gc); |
2956 | 4204 } |
4205 | |
4206 /*---------------------------------------*/ | |
4207 /* End Jabber "set info" (vCard) support */ | |
4208 /*---------------------------------------*/ | |
4209 | |
4210 /*----------------------------------------*/ | |
4211 /* Jabber "user registration" support */ | |
4212 /*----------------------------------------*/ | |
4213 | |
4214 /* | |
4215 * Three of the following four functions duplicate much of what | |
4216 * exists elsewhere: | |
4217 * | |
4218 * jabber_handleregresp() | |
4219 * gjab_reqreg() | |
4220 * jabber_handle_registration_state() | |
4221 * | |
4222 * It may be that an additional flag could be added to one of | |
4223 * the "local" structs and the duplicated code modified to | |
4224 * account for it--thus eliminating the duplication. Then again: | |
4225 * doing it the way it is may be much cleaner. | |
4226 * | |
4227 * TBD: Code to support requesting additional information server | |
4228 * wants at registration--incl. dialog. | |
4229 */ | |
4230 | |
4231 /* | |
4232 * Like jabber_handlepacket(), only different | |
4233 */ | |
4234 static void jabber_handleregresp(gjconn gjc, jpacket p) | |
4235 { | |
4236 if (jpacket_subtype(p) == JPACKET__RESULT) { | |
4237 xmlnode querynode; | |
4238 | |
4239 if((querynode = xmlnode_get_tag(p->x, "query")) != NULL) { | |
4240 char *xmlns; | |
4241 | |
4242 /* we damn well *better* have this! */ | |
4243 if((xmlns = xmlnode_get_attrib(querynode, "xmlns")) != NULL && | |
4244 strcmp(xmlns, NS_REGISTER) == 0) { | |
4245 | |
4246 char *tag; | |
4247 xmlnode child = xmlnode_get_firstchild(querynode); | |
4248 | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
4249 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
4250 "got registration requirments response!\n"); |
2956 | 4251 |
4252 while(child != NULL) { | |
4253 if((tag = xmlnode_get_name(child)) != NULL) { | |
4254 char *data; | |
4255 | |
4256 fprintf(stderr, "DBG: got node: \"%s\"\n", tag); | |
4257 fflush(stderr); | |
4258 | |
4259 if((data = xmlnode_get_data(child)) != NULL) { | |
4260 fprintf(stderr, "DBG: got data: \"%s\"\n", data); | |
4261 fflush(stderr); | |
4262 } | |
4263 } | |
4264 child = xmlnode_get_nextsibling(child); | |
4265 } | |
4266 } | |
4267 } else { | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
4268 gaim_debug(GAIM_DEBUG_INFO, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
4269 "registration successful!\n"); |
2956 | 4270 |
5572 | 4271 gaim_connection_notice(GJ_GC(gjc), _("Server Registration successful!")); |
5578
847ad796326d
[gaim-migrate @ 5982]
Christian Hammond <chipx86@chipx86.com>
parents:
5572
diff
changeset
|
4272 gaim_connection_destroy(GJ_GC(gjc)); |
2956 | 4273 } |
4274 | |
4275 } else { | |
4276 xmlnode xerr; | |
4277 char *errmsg = NULL; | |
4278 int errcode = 0; | |
4279 | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
4280 gaim_debug(GAIM_DEBUG_ERROR, "jabber", "registration failed\n"); |
2956 | 4281 xerr = xmlnode_get_tag(p->x, "error"); |
4282 if (xerr) { | |
4283 char msg[BUF_LONG]; | |
4284 errmsg = xmlnode_get_data(xerr); | |
4285 if (xmlnode_get_attrib(xerr, "code")) { | |
4286 errcode = atoi(xmlnode_get_attrib(xerr, "code")); | |
6321 | 4287 g_snprintf(msg, sizeof(msg), _("Error %d: %s"), errcode, errmsg); |
2956 | 4288 } else |
4289 g_snprintf(msg, sizeof(msg), "%s", errmsg); | |
5572 | 4290 gaim_connection_error(GJ_GC(gjc), msg); |
2956 | 4291 } else { |
5572 | 4292 gaim_connection_error(GJ_GC(gjc), _("Unknown registration error")); |
2956 | 4293 } |
4294 } | |
4295 } | |
4296 | |
4297 /* | |
4298 * Like gjab_reqauth(), only different | |
4299 */ | |
4300 static void gjab_reqreg(gjconn gjc) | |
4301 { | |
4302 xmlnode x, y, z; | |
4303 char *user; | |
4304 | |
4305 if (!gjc) | |
4306 return; | |
4307 | |
4308 x = jutil_iqnew(JPACKET__SET, NS_REGISTER); | |
4309 y = xmlnode_get_tag(x, "query"); | |
4310 | |
4311 user = gjc->user->user; | |
4312 | |
4313 if (user) { | |
4314 z = xmlnode_insert_tag(y, "username"); | |
4315 xmlnode_insert_cdata(z, user, -1); | |
4316 } | |
4317 z = xmlnode_insert_tag(y, "password"); | |
4318 xmlnode_insert_cdata(z, gjc->pass, -1); | |
4319 | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
4320 gaim_debug(GAIM_DEBUG_MISC, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
4321 "jabber: registration packet: %s\n", xmlnode2str(x)); |
2956 | 4322 gjab_send(gjc, x); |
4323 xmlnode_free(x); | |
4324 } | |
4325 | |
4326 /* | |
4327 * Like jabber_handlestate(), only different | |
4328 */ | |
4329 static void jabber_handle_registration_state(gjconn gjc, int state) | |
4330 { | |
4331 switch (state) { | |
4332 case JCONN_STATE_OFF: | |
3074 | 4333 if(gjc->was_connected) { |
5572 | 4334 gaim_connection_error(GJ_GC(gjc), _("Connection lost")); |
3074 | 4335 } else { |
5572 | 4336 gaim_connection_error(GJ_GC(gjc), _("Unable to connect")); |
3074 | 4337 } |
2956 | 4338 break; |
4339 case JCONN_STATE_CONNECTED: | |
3074 | 4340 gjc->was_connected = 1; |
2956 | 4341 /* |
4342 * TBD? | |
6106 | 4343 gaim_connection_update_progress(GJ_GC(gjc), _("Connected"), |
4344 2, JABBER_CONNECT_STEPS); | |
2956 | 4345 */ |
4346 break; | |
4347 case JCONN_STATE_ON: | |
4348 /* | |
4349 * TBD? | |
6106 | 4350 gaim_connection_update_progress(GJ_GC(gjc), _("Authenticating"), |
4351 _("Requesting Authentication Method"), 3, | |
4352 JABBER_CONNECT_STEPS); | |
2956 | 4353 */ |
4354 gjab_reqreg(gjc); | |
4355 /* | |
4356 * TBD: A work-in-progress | |
4357 gjab_reqregreqs(gjc); | |
4358 */ | |
4359 break; | |
4360 default: | |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
4361 gaim_debug(GAIM_DEBUG_MISC, "jabber", "state change: %d\n", state); |
2956 | 4362 } |
4363 return; | |
4364 } | |
4365 | |
4366 /* | |
4367 * Like jabber_login(), only different | |
4368 */ | |
5572 | 4369 void jabber_register_user(GaimAccount *account) |
2956 | 4370 { |
6581 | 4371 GaimConnection *gc = gaim_account_get_connection(account); |
2956 | 4372 struct jabber_data *jd = gc->proto_data = g_new0(struct jabber_data, 1); |
4917 | 4373 char *loginname = create_valid_jid(account->username, DEFAULT_SERVER, "Gaim"); |
2956 | 4374 |
4375 /* | |
4376 * These do nothing during registration | |
4377 */ | |
3311 | 4378 jd->buddies = NULL; |
2956 | 4379 jd->chats = NULL; |
4380 | |
4491 | 4381 if ((jd->gjc = gjab_new(loginname, account->password, gc)) == NULL) { |
2956 | 4382 g_free(loginname); |
5223
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
4383 gaim_debug(GAIM_DEBUG_ERROR, "jabber", |
e2e5bc3ca705
[gaim-migrate @ 5593]
Christian Hammond <chipx86@chipx86.com>
parents:
5205
diff
changeset
|
4384 "unable to connect (jab_new failed)\n"); |
5572 | 4385 gaim_connection_error(gc, _("Unable to connect")); |
2956 | 4386 } else { |
4387 gjab_state_handler(jd->gjc, jabber_handle_registration_state); | |
4388 gjab_packet_handler(jd->gjc, jabber_handleregresp); | |
4389 jd->gjc->queries = NULL; | |
4390 gjab_start(jd->gjc); | |
4391 } | |
4392 | |
4393 g_free(loginname); | |
4394 } | |
4395 | |
4396 /*----------------------------------------*/ | |
4397 /* End Jabber "user registration" support */ | |
4398 /*----------------------------------------*/ | |
4399 | |
5572 | 4400 static GList *jabber_actions(GaimConnection *gc) |
2956 | 4401 { |
4402 GList *m = NULL; | |
4333 | 4403 struct proto_actions_menu *pam; |
4404 | |
4405 pam = g_new0(struct proto_actions_menu, 1); | |
4406 pam->label = _("Set User Info"); | |
4407 pam->callback = jabber_setup_set_info; | |
4408 pam->gc = gc; | |
4409 m = g_list_append(m, pam); | |
4410 | |
2956 | 4411 /* |
4333 | 4412 pam = g_new0(struct proto_actions_menu, 1); |
4413 pam->label = _("Set Dir Info"); | |
4414 pam->callback = show_set_dir; | |
4415 pam->gc = gc; | |
4416 m = g_list_append(m, pam); | |
3257 | 4417 */ |
4333 | 4418 |
4419 pam = g_new0(struct proto_actions_menu, 1); | |
4420 pam->label = _("Change Password"); | |
4421 pam->callback = show_change_passwd; | |
4422 pam->gc = gc; | |
4423 m = g_list_append(m, pam); | |
2956 | 4424 |
4425 return m; | |
4426 } | |
4427 | |
5205
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4428 static GaimPluginProtocolInfo prpl_info = |
2086 | 4429 { |
5205
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4430 GAIM_PROTO_JABBER, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4431 OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_CHAT_TOPIC, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4432 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4433 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4434 jabber_list_icon, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4435 jabber_list_emblems, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4436 jabber_status_text, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4437 jabber_tooltip_text, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4438 jabber_away_states, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4439 jabber_actions, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4440 jabber_buddy_menu, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4441 jabber_chat_info, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4442 jabber_login, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4443 jabber_close, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4444 jabber_send_im, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4445 jabber_set_info, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4446 jabber_send_typing, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4447 jabber_get_info, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4448 jabber_set_away, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4449 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4450 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4451 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4452 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4453 jabber_set_idle, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4454 jabber_change_passwd, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4455 jabber_add_buddy, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4456 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4457 jabber_remove_buddy, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4458 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4459 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4460 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4461 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4462 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4463 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4464 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4465 jabber_join_chat, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4466 jabber_chat_invite, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4467 jabber_chat_leave, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4468 jabber_chat_whisper, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4469 jabber_chat_send, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4470 jabber_keepalive, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4471 jabber_register_user, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4472 jabber_get_cb_info, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4473 jabber_get_cb_away_msg, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4474 jabber_alias_buddy, |
5957 | 4475 jabber_group_change, |
5205
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4476 jabber_rename_group, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4477 NULL, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4478 jabber_convo_closed, |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4479 jabber_normalize |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4480 }; |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4481 |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4482 static GaimPluginInfo info = |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4483 { |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4484 2, /**< api_version */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4485 GAIM_PLUGIN_PROTOCOL, /**< type */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4486 NULL, /**< ui_requirement */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4487 0, /**< flags */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4488 NULL, /**< dependencies */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4489 GAIM_PRIORITY_DEFAULT, /**< priority */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4490 |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4491 "prpl-jabber", /**< id */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4492 "Jabber", /**< name */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4493 VERSION, /**< version */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4494 /** summary */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4495 N_("Jabber Protocol Plugin"), |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4496 /** description */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4497 N_("Jabber Protocol Plugin"), |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4498 NULL, /**< author */ |
6371
8f94cce8faa5
[gaim-migrate @ 6876]
Christian Hammond <chipx86@chipx86.com>
parents:
6357
diff
changeset
|
4499 GAIM_WEBSITE, /**< homepage */ |
5205
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4500 |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4501 NULL, /**< load */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4502 NULL, /**< unload */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4503 NULL, /**< destroy */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4504 |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4505 NULL, /**< ui_info */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4506 &prpl_info /**< extra_info */ |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4507 }; |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4508 |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4509 static void |
5920
7d385de2f9cd
[gaim-migrate @ 6360]
Christian Hammond <chipx86@chipx86.com>
parents:
5894
diff
changeset
|
4510 init_plugin(GaimPlugin *plugin) |
5205
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4511 { |
5638
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4512 GaimAccountUserSplit *split; |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4513 GaimAccountOption *option; |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4514 |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4515 /* Splits */ |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4516 split = gaim_account_user_split_new(_("Server"), "jabber.org", '@'); |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4517 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4518 |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4519 split = gaim_account_user_split_new(_("Resource"), "Gaim", '/'); |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4520 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4521 |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4522 /* Account Options */ |
6764 | 4523 |
4524 if(gaim_ssl_is_supported()) { | |
6880 | 4525 option = gaim_account_option_bool_new(_("Use SSL"), "old_ssl", FALSE); |
6764 | 4526 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, |
4527 option); | |
4528 } | |
4529 | |
5638
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4530 option = gaim_account_option_int_new(_("Port"), "port", DEFAULT_PORT); |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4531 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4532 option); |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4533 |
5685
43ea75092684
[gaim-migrate @ 6106]
Christian Hammond <chipx86@chipx86.com>
parents:
5681
diff
changeset
|
4534 option = gaim_account_option_string_new(_("Connect server"), |
5638
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4535 "connect_server", NULL); |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4536 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, |
0bdfa28c678e
[gaim-migrate @ 6047]
Christian Hammond <chipx86@chipx86.com>
parents:
5613
diff
changeset
|
4537 option); |
5205
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4538 |
fefad67de2c7
[gaim-migrate @ 5573]
Christian Hammond <chipx86@chipx86.com>
parents:
5174
diff
changeset
|
4539 my_protocol = plugin; |
2086 | 4540 } |
4541 | |
5920
7d385de2f9cd
[gaim-migrate @ 6360]
Christian Hammond <chipx86@chipx86.com>
parents:
5894
diff
changeset
|
4542 GAIM_INIT_PLUGIN(jabber, init_plugin, info); |