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