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