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