Mercurial > pidgin.yaz
annotate src/protocols/rendezvous/rendezvous.c @ 10812:d087e928ffd1
[gaim-migrate @ 12465]
" A variety of spacing normalization I've done as I've
navigated the source making other changes. The specific
changes should be uncontroversial. I'm submitting these to
shrink the deltas between my local tree and the CVS
source. If spacing changes are unwelcome as a general
rule, let me know." --rlaager
I said not to do this sort of patch often.
also a spelling fix.
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Mon, 11 Apr 2005 04:32:26 +0000 |
parents | 1da76f22c750 |
children | c94f40ffcafb |
rev | line source |
---|---|
8487 | 1 /* |
2 * gaim - Rendezvous Protocol Plugin | |
3 * | |
4 * Gaim is the legal property of its developers, whose names are too numerous | |
5 * to list here. Please refer to the COPYRIGHT file distributed with this | |
6 * source distribution. | |
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 #include "internal.h" | |
23 | |
24 #include "account.h" | |
25 #include "accountopt.h" | |
26 #include "blist.h" | |
27 #include "conversation.h" | |
10705 | 28 #include "cipher.h" |
8487 | 29 #include "debug.h" |
8834 | 30 #include "network.h" |
8487 | 31 #include "prpl.h" |
9954 | 32 #include "version.h" |
8487 | 33 |
10321 | 34 #include "direct.h" |
35 #include "mdns.h" | |
9965 | 36 #include "rendezvous.h" |
10321 | 37 #include "util.h" |
8487 | 38 |
39 /****************************/ | |
40 /* Utility Functions */ | |
41 /****************************/ | |
10321 | 42 static void |
43 rendezvous_buddy_free(gpointer data) | |
8487 | 44 { |
45 RendezvousBuddy *rb = data; | |
46 | |
10321 | 47 if (rb->fd >= 0) |
48 close(rb->fd); | |
49 if (rb->watcher >= 0) | |
50 gaim_input_remove(rb->watcher); | |
51 | |
8487 | 52 g_free(rb->firstandlast); |
53 g_free(rb->msg); | |
54 g_free(rb); | |
55 } | |
56 | |
8546 | 57 /** |
8487 | 58 * Extract the "user@host" name from a full presence domain |
59 * of the form "user@host._presence._tcp.local" | |
60 * | |
61 * @return If the domain is NOT a _presence._tcp.local domain | |
62 * then return NULL. Otherwise return a newly allocated | |
63 * null-terminated string containing the "user@host" for | |
64 * the given domain. This string should be g_free'd | |
65 * when no longer needed. | |
66 */ | |
10321 | 67 static gchar * |
68 rendezvous_extract_name(gchar *domain) | |
8487 | 69 { |
70 gchar *ret, *suffix; | |
71 | |
10321 | 72 if (!gaim_str_has_suffix(domain, "._presence._tcp.local")) |
8487 | 73 return NULL; |
74 | |
75 suffix = strstr(domain, "._presence._tcp.local"); | |
76 ret = g_strndup(domain, suffix - domain); | |
77 | |
78 return ret; | |
79 } | |
80 | |
81 /****************************/ | |
82 /* Buddy List Functions */ | |
83 /****************************/ | |
8612 | 84 |
10549 | 85 static RendezvousBuddy * |
86 rendezvous_find_or_create_rendezvousbuddy(GaimConnection *gc, const char *name) | |
87 { | |
88 RendezvousData *rd = gc->proto_data; | |
89 RendezvousBuddy *rb; | |
90 | |
91 rb = g_hash_table_lookup(rd->buddies, name); | |
92 if (rb == NULL) { | |
93 rb = g_malloc0(sizeof(RendezvousBuddy)); | |
94 rb->fd = -1; | |
95 rb->watcher = -1; | |
96 g_hash_table_insert(rd->buddies, g_strdup(name), rb); | |
97 } | |
98 | |
99 return rb; | |
100 } | |
101 | |
10321 | 102 static void |
103 rendezvous_addtolocal(GaimConnection *gc, const char *name, const char *domain) | |
8487 | 104 { |
105 GaimAccount *account = gaim_connection_get_account(gc); | |
106 GaimBuddy *b; | |
107 GaimGroup *g; | |
108 | |
109 g = gaim_find_group(domain); | |
110 if (g == NULL) { | |
111 g = gaim_group_new(domain); | |
112 gaim_blist_add_group(g, NULL); | |
113 } | |
114 | |
115 b = gaim_find_buddy_in_group(account, name, g); | |
116 if (b != NULL) | |
117 return; | |
118 | |
119 b = gaim_buddy_new(account, name, NULL); | |
10549 | 120 gaim_blist_node_set_flags((GaimBlistNode *)b, GAIM_BLIST_NODE_FLAG_NO_SAVE); |
9817 | 121 /* gaim_blist_node_set_flag(b, GAIM_BLIST_NODE_FLAG_NO_SAVE); */ |
8487 | 122 gaim_blist_add_buddy(b, NULL, g, NULL); |
10009 | 123 gaim_prpl_got_user_status(account, b->name, "online", NULL); |
8612 | 124 |
125 #if 0 | |
10596 | 126 /* Remove the buddy if the TTL on their PTR record expires */ |
8612 | 127 RendezvousBuddy *rb; |
10549 | 128 rb = rendezvous_find_or_create_rendezvousbuddy(gc, name); |
8612 | 129 rb->ttltimer = gaim_timeout_add(time * 10000, rendezvous_buddy_timeout, gc); |
130 | |
131 gaim_timeout_remove(rb->ttltimer); | |
132 rb->ttltimer = 0; | |
133 #endif | |
8487 | 134 } |
135 | |
10321 | 136 static void |
137 rendezvous_removefromlocal(GaimConnection *gc, const char *name, const char *domain) | |
8487 | 138 { |
139 GaimAccount *account = gaim_connection_get_account(gc); | |
140 GaimBuddy *b; | |
141 GaimGroup *g; | |
142 | |
143 g = gaim_find_group(domain); | |
144 if (g == NULL) | |
145 return; | |
146 | |
147 b = gaim_find_buddy_in_group(account, name, g); | |
148 if (b == NULL) | |
149 return; | |
150 | |
10009 | 151 gaim_prpl_got_user_status(account, b->name, "offline", NULL); |
8487 | 152 gaim_blist_remove_buddy(b); |
8546 | 153 /* XXX - This results in incorrect group counts--needs to be fixed in the core */ |
10320 | 154 /* XXX - We also need to call remove_idle_buddy() in server.c for idle buddies */ |
8612 | 155 |
156 /* | |
157 * XXX - Instead of removing immediately, wait 10 seconds and THEN remove | |
158 * them. If you do it immediately you don't see the door close icon. | |
159 */ | |
8487 | 160 } |
161 | |
10321 | 162 static void |
163 rendezvous_removeallfromlocal(GaimConnection *gc) | |
8487 | 164 { |
165 GaimAccount *account = gaim_connection_get_account(gc); | |
166 GaimBuddyList *blist; | |
167 GaimBlistNode *gnode, *cnode, *bnode; | |
168 GaimBuddy *b; | |
169 | |
170 /* Go through and remove all buddies that belong to this account */ | |
171 if ((blist = gaim_get_blist()) != NULL) { | |
172 for (gnode = blist->root; gnode; gnode = gnode->next) { | |
173 if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
174 continue; | |
175 for (cnode = gnode->child; cnode; cnode = cnode->next) { | |
176 if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) | |
177 continue; | |
178 for (bnode = cnode->child; bnode; bnode = bnode->next) { | |
179 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode)) | |
180 continue; | |
181 b = (GaimBuddy *)bnode; | |
182 if (b->account != account) | |
183 continue; | |
10009 | 184 gaim_prpl_got_user_status(account, b->name, "offline", NULL); |
8487 | 185 gaim_blist_remove_buddy(b); |
186 } | |
187 } | |
188 } | |
189 } | |
190 } | |
191 | |
10596 | 192 static gboolean |
193 rendezvous_find_buddy_by_host(gpointer key, gpointer value, gpointer user_data) | |
194 { | |
195 const gchar *domain; | |
196 | |
197 if (key == NULL) | |
198 return FALSE; | |
199 | |
200 domain = strchr(key, '@'); | |
201 if (domain == NULL) | |
202 return FALSE; | |
203 domain++; | |
204 | |
205 return !strcasecmp(user_data, domain); | |
206 } | |
207 | |
10321 | 208 static void |
209 rendezvous_handle_rr_a(GaimConnection *gc, ResourceRecord *rr, const gchar *name) | |
8834 | 210 { |
10596 | 211 RendezvousData *rd = gc->proto_data; |
8834 | 212 RendezvousBuddy *rb; |
213 ResourceRecordRDataSRV *rdata; | |
10596 | 214 const gchar *end; |
215 gchar *domain; | |
216 | |
217 /* | |
218 * Remove the trailing ".local" from the domain. If there is no | |
219 * trailing ".local" then do nothing and exit | |
220 */ | |
221 end = g_strrstr(name, ".local"); | |
222 if (end == NULL) | |
223 return; | |
224 | |
225 domain = g_strndup(name, (gpointer)end - (gpointer)name); | |
226 rb = g_hash_table_find(rd->buddies, rendezvous_find_buddy_by_host, domain); | |
227 g_free(domain); | |
228 | |
229 if (rb == NULL) | |
230 return; | |
8834 | 231 |
232 rdata = rr->rdata; | |
233 | |
10549 | 234 memcpy(rb->ipv4, rdata, 4); |
8834 | 235 } |
236 | |
10321 | 237 static void |
238 rendezvous_handle_rr_txt(GaimConnection *gc, ResourceRecord *rr, const gchar *name) | |
8487 | 239 { |
10011 | 240 GaimAccount *account = gaim_connection_get_account(gc); |
8487 | 241 RendezvousBuddy *rb; |
8806 | 242 GSList *rdata; |
243 ResourceRecordRDataTXTNode *node1, *node2; | |
8487 | 244 |
8594 | 245 rdata = rr->rdata; |
246 | |
247 /* Don't do a damn thing if the version is greater than 1 */ | |
8806 | 248 node1 = mdns_txt_find(rdata, "version"); |
249 if ((node1 == NULL) || (node1->value == NULL) || (strcmp(node1->value, "1"))) | |
8594 | 250 return; |
251 | |
10549 | 252 rb = rendezvous_find_or_create_rendezvousbuddy(gc, name); |
8487 | 253 |
8806 | 254 node1 = mdns_txt_find(rdata, "1st"); |
255 node2 = mdns_txt_find(rdata, "last"); | |
8487 | 256 g_free(rb->firstandlast); |
257 rb->firstandlast = g_strdup_printf("%s%s%s", | |
8806 | 258 (node1 && node1->value ? node1->value : ""), |
259 (node1 && node1->value && node2 && node2->value ? " " : ""), | |
260 (node2 && node2->value ? node2->value : "")); | |
8487 | 261 serv_got_alias(gc, name, rb->firstandlast); |
262 | |
8806 | 263 node1 = mdns_txt_find(rdata, "aim"); |
264 if ((node1 != NULL) && (node1->value != NULL)) { | |
8487 | 265 g_free(rb->aim); |
8806 | 266 rb->aim = g_strdup(node1->value); |
8487 | 267 } |
268 | |
8594 | 269 /* |
270 * We only want to use this port as a back-up. Ideally the port | |
271 * is specified in a separate, SRV resource record. | |
272 */ | |
273 if (rb->p2pjport == 0) { | |
8806 | 274 node1 = mdns_txt_find(rdata, "port.p2pj"); |
275 if ((node1 != NULL) && (node1->value)) | |
276 rb->p2pjport = atoi(node1->value); | |
8594 | 277 } |
8487 | 278 |
9775 | 279 node1 = mdns_txt_find(rdata, "status"); |
8806 | 280 if ((node1 != NULL) && (node1->value != NULL)) { |
281 if (!strcmp(node1->value, "avail")) { | |
8487 | 282 /* Available */ |
283 rb->status = 0; | |
8806 | 284 } else if (!strcmp(node1->value, "away")) { |
8487 | 285 /* Idle */ |
8806 | 286 node2 = mdns_txt_find(rdata, "away"); |
287 if ((node2 != NULL) && (node2->value)) { | |
9289 | 288 /* Time is seconds since January 1st 2001 GMT */ |
8806 | 289 rb->idle = atoi(node2->value); |
9289 | 290 rb->idle += 978307200; /* convert to seconds-since-epoch */ |
8806 | 291 } |
8487 | 292 rb->status = UC_IDLE; |
10549 | 293 /* TODO: Do this when the user is added to the buddy list? Definitely not here! */ |
294 /* gaim_prpl_got_user_idle(account, name, TRUE, rb->idle); */ | |
8806 | 295 } else if (!strcmp(node1->value, "dnd")) { |
8487 | 296 /* Away */ |
297 rb->status = UC_UNAVAILABLE; | |
298 } | |
10011 | 299 gaim_prpl_got_user_status(account, name, "online", NULL); |
9965 | 300 /* XXX - Idle time is rb->idle and status is rb->status */ |
8487 | 301 } |
302 | |
8806 | 303 node1 = mdns_txt_find(rdata, "msg"); |
304 if ((node1 != NULL) && (node1->value != NULL)) { | |
8487 | 305 g_free(rb->msg); |
8806 | 306 rb->msg = g_strdup(node1->value); |
8487 | 307 } |
8594 | 308 } |
8546 | 309 |
10321 | 310 static void |
311 rendezvous_handle_rr_aaaa(GaimConnection *gc, ResourceRecord *rr, const gchar *name) | |
312 { | |
10596 | 313 RendezvousData *rd = gc->proto_data; |
10321 | 314 RendezvousBuddy *rb; |
315 ResourceRecordRDataSRV *rdata; | |
10596 | 316 const gchar *end; |
317 gchar *domain; | |
318 | |
319 /* | |
320 * Remove the trailing ".local" from the domain. If there is no | |
321 * trailing ".local" then do nothing and exit | |
322 */ | |
323 end = g_strrstr(name, ".local"); | |
324 if (end == NULL) | |
325 return; | |
326 | |
327 domain = g_strndup(name, (gpointer)end - (gpointer)name); | |
328 rb = g_hash_table_find(rd->buddies, rendezvous_find_buddy_by_host, domain); | |
329 g_free(domain); | |
330 | |
331 if (rb == NULL) | |
332 return; | |
10321 | 333 |
334 rdata = rr->rdata; | |
335 | |
10549 | 336 memcpy(rb->ipv6, rdata, 16); |
10321 | 337 } |
338 | |
339 static void | |
340 rendezvous_handle_rr_srv(GaimConnection *gc, ResourceRecord *rr, const gchar *name) | |
8594 | 341 { |
342 RendezvousBuddy *rb; | |
8806 | 343 ResourceRecordRDataSRV *rdata; |
8594 | 344 |
345 rdata = rr->rdata; | |
346 | |
10549 | 347 rb = rendezvous_find_or_create_rendezvousbuddy(gc, name); |
8594 | 348 |
349 rb->p2pjport = rdata->port; | |
8487 | 350 } |
351 | |
352 /* | |
353 * Parse a resource record and do stuff if we need to. | |
354 */ | |
10321 | 355 static void |
356 rendezvous_handle_rr(GaimConnection *gc, ResourceRecord *rr) | |
8487 | 357 { |
8636 | 358 RendezvousData *rd = gc->proto_data; |
8487 | 359 gchar *name; |
360 | |
10321 | 361 gaim_debug_misc("rendezvous", "Parsing resource record with domain name %s and type %d\n", rr->name, rr->type); |
8594 | 362 |
8834 | 363 switch (rr->type) { |
364 case RENDEZVOUS_RRTYPE_A: { | |
10596 | 365 rendezvous_handle_rr_a(gc, rr, rr->name); |
8834 | 366 } break; |
8487 | 367 |
368 case RENDEZVOUS_RRTYPE_NULL: { | |
8834 | 369 name = rendezvous_extract_name(rr->name); |
370 if (name != NULL) { | |
8487 | 371 if (rr->rdlength > 0) { |
372 /* Data is a buddy icon */ | |
373 gaim_buddy_icons_set_for_user(gaim_connection_get_account(gc), name, rr->rdata, rr->rdlength); | |
374 } | |
375 | |
376 g_free(name); | |
377 } | |
378 } break; | |
379 | |
380 case RENDEZVOUS_RRTYPE_PTR: { | |
381 gchar *rdata = rr->rdata; | |
8834 | 382 |
383 name = rendezvous_extract_name(rdata); | |
384 if (name != NULL) { | |
8636 | 385 if (rr->ttl > 0) { |
386 /* Add them to our buddy list and request their icon */ | |
8487 | 387 rendezvous_addtolocal(gc, name, "Rendezvous"); |
8636 | 388 mdns_query(rd->fd, rdata, RENDEZVOUS_RRTYPE_NULL); |
389 } else { | |
390 /* Remove them from our buddy list */ | |
8487 | 391 rendezvous_removefromlocal(gc, name, "Rendezvous"); |
8636 | 392 } |
8487 | 393 g_free(name); |
394 } | |
395 } break; | |
396 | |
397 case RENDEZVOUS_RRTYPE_TXT: { | |
8834 | 398 name = rendezvous_extract_name(rr->name); |
399 if (name != NULL) { | |
8487 | 400 rendezvous_handle_rr_txt(gc, rr, name); |
401 g_free(name); | |
402 } | |
403 } break; | |
8594 | 404 |
10321 | 405 case RENDEZVOUS_RRTYPE_AAAA: { |
10596 | 406 rendezvous_handle_rr_aaaa(gc, rr, rr->name); |
10321 | 407 } break; |
408 | |
8594 | 409 case RENDEZVOUS_RRTYPE_SRV: { |
8834 | 410 name = rendezvous_extract_name(rr->name); |
411 if (name != NULL) { | |
8594 | 412 rendezvous_handle_rr_srv(gc, rr, name); |
413 g_free(name); | |
414 } | |
415 } break; | |
8487 | 416 } |
417 } | |
418 | |
419 /****************************/ | |
8735
92cbf9713795
[gaim-migrate @ 9490]
Christian Hammond <chipx86@chipx86.com>
parents:
8721
diff
changeset
|
420 /* Connection Functions */ |
8487 | 421 /****************************/ |
10321 | 422 static void |
423 rendezvous_callback(gpointer data, gint source, GaimInputCondition condition) | |
8487 | 424 { |
425 GaimConnection *gc = data; | |
426 RendezvousData *rd = gc->proto_data; | |
427 DNSPacket *dns; | |
8806 | 428 GSList *cur; |
8487 | 429 |
430 gaim_debug_misc("rendezvous", "Received rendezvous datagram\n"); | |
431 | |
432 dns = mdns_read(rd->fd); | |
433 if (dns == NULL) | |
434 return; | |
435 | |
436 /* Handle the DNS packet */ | |
8806 | 437 for (cur = dns->answers; cur != NULL; cur = cur->next) |
438 rendezvous_handle_rr(gc, cur->data); | |
439 for (cur = dns->authority; cur != NULL; cur = cur->next) | |
440 rendezvous_handle_rr(gc, cur->data); | |
441 for (cur = dns->additional; cur != NULL; cur = cur->next) | |
442 rendezvous_handle_rr(gc, cur->data); | |
8487 | 443 |
444 mdns_free(dns); | |
445 } | |
446 | |
10321 | 447 static void |
448 rendezvous_add_to_txt(RendezvousData *rd, const char *name, const char *value) | |
8629 | 449 { |
8631 | 450 ResourceRecordRDataTXTNode *node; |
451 node = g_malloc(sizeof(ResourceRecordRDataTXTNode)); | |
8629 | 452 node->name = g_strdup(name); |
453 node->value = value != NULL ? g_strdup(value) : NULL; | |
454 rd->mytxtdata = g_slist_append(rd->mytxtdata, node); | |
455 } | |
456 | |
10321 | 457 static guchar * |
458 rendezvous_read_icon_data(const char *filename, unsigned short *length) | |
9416 | 459 { |
460 struct stat st; | |
461 FILE *file; | |
462 guchar *data; | |
463 | |
464 *length = 0; | |
465 | |
466 g_return_val_if_fail(filename != NULL, NULL); | |
467 | |
10589
0f7452b1f777
[gaim-migrate @ 11994]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10549
diff
changeset
|
468 if (g_stat(filename, &st)) |
9416 | 469 return NULL; |
470 | |
10589
0f7452b1f777
[gaim-migrate @ 11994]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10549
diff
changeset
|
471 if (!(file = g_fopen(filename, "rb"))) |
9416 | 472 return NULL; |
473 | |
474 *length = st.st_size; | |
475 data = g_malloc(*length); | |
476 fread(data, 1, *length, file); | |
477 fclose(file); | |
478 | |
479 return data; | |
480 } | |
481 | |
10321 | 482 static void |
483 rendezvous_add_to_txt_iconhash(RendezvousData *rd, const char *iconfile) | |
9416 | 484 { |
485 guchar *icondata; | |
486 unsigned short iconlength; | |
487 unsigned char hash[20]; | |
488 gchar *base16; | |
489 | |
490 g_return_if_fail(rd != NULL); | |
491 | |
492 if (iconfile == NULL) | |
493 return; | |
494 | |
495 icondata = rendezvous_read_icon_data(iconfile, &iconlength); | |
10705 | 496 gaim_cipher_digest_region("sha1", (guint8 *)icondata, iconlength, sizeof(hash), hash, NULL); |
9416 | 497 g_free(icondata); |
498 | |
499 base16 = gaim_base16_encode(hash, 20); | |
500 rendezvous_add_to_txt(rd, "phsh", base16); | |
501 g_free(base16); | |
502 } | |
503 | |
10321 | 504 static void |
505 rendezvous_send_icon(GaimConnection *gc) | |
8636 | 506 { |
507 RendezvousData *rd = gc->proto_data; | |
508 GaimAccount *account = gaim_connection_get_account(gc); | |
509 const char *iconfile = gaim_account_get_buddy_icon(account); | |
510 unsigned char *rdata; | |
511 unsigned short rdlength; | |
512 gchar *myname; | |
513 | |
514 if (iconfile == NULL) | |
515 return; | |
516 | |
9416 | 517 rdata = rendezvous_read_icon_data(iconfile, &rdlength); |
8636 | 518 |
519 myname = g_strdup_printf("%s._presence._tcp.local", gaim_account_get_username(account)); | |
520 mdns_advertise_null(rd->fd, myname, rdata, rdlength); | |
521 g_free(myname); | |
8695 | 522 |
523 g_free(rdata); | |
8636 | 524 } |
525 | |
10321 | 526 static void |
527 rendezvous_send_online(GaimConnection *gc) | |
8629 | 528 { |
529 RendezvousData *rd = gc->proto_data; | |
530 GaimAccount *account = gaim_connection_get_account(gc); | |
10549 | 531 const gchar *me, *myip; |
10321 | 532 gchar *myname, *mycomp, *myport; |
10549 | 533 gchar **mysplitip; |
10321 | 534 unsigned char myipv4[4]; |
8629 | 535 |
8631 | 536 me = gaim_account_get_username(account); |
537 myname = g_strdup_printf("%s._presence._tcp.local", me); | |
538 mycomp = g_strdup_printf("%s.local", strchr(me, '@') + 1); | |
10321 | 539 myport = g_strdup_printf("%d", rd->listener_port); |
8631 | 540 |
10549 | 541 myip = gaim_network_get_local_system_ip(-1); |
542 mysplitip = g_strsplit(myip, ".", 0); | |
543 myipv4[0] = atoi(mysplitip[0]); | |
544 myipv4[1] = atoi(mysplitip[1]); | |
545 myipv4[2] = atoi(mysplitip[2]); | |
546 myipv4[3] = atoi(mysplitip[3]); | |
547 g_strfreev(mysplitip); | |
548 | |
10321 | 549 mdns_advertise_a(rd->fd, mycomp, myipv4); |
8631 | 550 mdns_advertise_ptr(rd->fd, "_presence._tcp.local", myname); |
10321 | 551 mdns_advertise_srv(rd->fd, myname, rd->listener_port, mycomp); |
8629 | 552 |
553 rendezvous_add_to_txt(rd, "txtvers", "1"); | |
554 rendezvous_add_to_txt(rd, "status", "avail"); | |
8631 | 555 /* rendezvous_add_to_txt(rd, "vc", "A!"); */ |
9416 | 556 rendezvous_add_to_txt_iconhash(rd, gaim_account_get_buddy_icon(account)); |
8629 | 557 rendezvous_add_to_txt(rd, "1st", gaim_account_get_string(account, "first", "Gaim")); |
8631 | 558 if (gaim_account_get_bool(account, "shareaim", FALSE)) { |
559 GList *l; | |
560 GaimAccount *cur; | |
561 for (l = gaim_accounts_get_all(); l != NULL; l = l->next) { | |
562 cur = (GaimAccount *)l->data; | |
563 if (!strcmp(gaim_account_get_protocol_id(cur), "prpl-oscar")) { | |
10596 | 564 rendezvous_add_to_txt(rd, "AIM", gaim_normalize(cur, gaim_account_get_username(cur))); |
8631 | 565 break; |
566 } | |
567 } | |
568 } | |
8629 | 569 rendezvous_add_to_txt(rd, "version", "1"); |
8631 | 570 rendezvous_add_to_txt(rd, "msg", "Groovin'"); |
10321 | 571 rendezvous_add_to_txt(rd, "port.p2pj", myport); |
8629 | 572 rendezvous_add_to_txt(rd, "last", gaim_account_get_string(account, "last", _("User"))); |
8631 | 573 mdns_advertise_txt(rd->fd, myname, rd->mytxtdata); |
8629 | 574 |
8636 | 575 rendezvous_send_icon(gc); |
576 | |
8631 | 577 g_free(myname); |
578 g_free(mycomp); | |
10321 | 579 g_free(myport); |
8629 | 580 } |
581 | |
10321 | 582 static void |
10596 | 583 rendezvous_send_offline(GaimConnection *gc) |
584 { | |
585 RendezvousData *rd = gc->proto_data; | |
586 GaimAccount *account = gaim_connection_get_account(gc); | |
587 const gchar *me; | |
588 gchar *myname; | |
589 | |
590 me = gaim_account_get_username(account); | |
591 myname = g_strdup_printf("%s._presence._tcp.local", me); | |
592 | |
593 mdns_advertise_ptr_with_ttl(rd->fd, "_presence._tcp.local", myname, 0); | |
594 } | |
595 | |
596 /***********************************/ | |
597 /* All the PRPL Callback Functions */ | |
598 /***********************************/ | |
599 static const char * | |
600 rendezvous_prpl_list_icon(GaimAccount *a, GaimBuddy *b) | |
601 { | |
602 return "rendezvous"; | |
603 } | |
604 | |
605 static void | |
606 rendezvous_prpl_list_emblems(GaimBuddy *b, const char **se, const char **sw, const char **nw, const char **ne) | |
607 { | |
608 if (GAIM_BUDDY_IS_ONLINE(b)) { | |
609 if (b->uc & UC_UNAVAILABLE) | |
610 *se = "away"; | |
611 } else { | |
612 *se = "offline"; | |
613 } | |
614 } | |
615 | |
616 static gchar * | |
617 rendezvous_prpl_status_text(GaimBuddy *b) | |
618 { | |
619 GaimConnection *gc = b->account->gc; | |
620 RendezvousData *rd = gc->proto_data; | |
621 RendezvousBuddy *rb; | |
622 gchar *ret; | |
623 | |
624 rb = g_hash_table_lookup(rd->buddies, b->name); | |
625 if ((rb == NULL) || (rb->msg == NULL)) | |
626 return NULL; | |
627 | |
628 ret = g_strdup(rb->msg); | |
629 | |
630 return ret; | |
631 } | |
632 | |
633 static gchar * | |
634 rendezvous_prpl_tooltip_text(GaimBuddy *b) | |
635 { | |
636 GaimConnection *gc = b->account->gc; | |
637 RendezvousData *rd = gc->proto_data; | |
638 RendezvousBuddy *rb; | |
639 GString *ret; | |
640 | |
641 rb = g_hash_table_lookup(rd->buddies, b->name); | |
642 if (rb == NULL) | |
643 return NULL; | |
644 | |
645 ret = g_string_new(""); | |
646 | |
647 if (rb->aim != NULL) | |
648 g_string_append_printf(ret, "\n<b>%s</b>: %s", _("AIM Screen name"), rb->aim); | |
649 | |
650 if (rb->msg != NULL) { | |
651 if (rb->status == UC_UNAVAILABLE) | |
652 g_string_append_printf(ret, "\n<b>%s</b>: %s", _("Away"), rb->msg); | |
653 else | |
654 g_string_append_printf(ret, "\n<b>%s</b>: %s", _("Available"), rb->msg); | |
655 } | |
656 | |
657 return g_string_free(ret, FALSE); | |
658 } | |
659 | |
660 static GList * | |
661 rendezvous_prpl_status_types(GaimAccount *account) | |
662 { | |
663 GList *status_types = NULL; | |
664 GaimStatusType *type; | |
665 | |
666 type = gaim_status_type_new_full(GAIM_STATUS_OFFLINE, "offline", _("Offline"), FALSE, TRUE, FALSE); | |
667 status_types = g_list_append(status_types, type); | |
668 | |
10719 | 669 type = gaim_status_type_new_with_attrs(GAIM_STATUS_ONLINE, "available", _("Available"), FALSE, TRUE, FALSE, "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), NULL); |
670 status_types = g_list_append(status_types, type); | |
671 | |
672 type = gaim_status_type_new_with_attrs(GAIM_STATUS_AWAY, "away", _("Away"), TRUE, TRUE, FALSE, "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), NULL); | |
10596 | 673 status_types = g_list_append(status_types, type); |
674 | |
675 return status_types; | |
676 } | |
677 | |
678 static void | |
10401 | 679 rendezvous_prpl_login(GaimAccount *account, GaimStatus *status) |
8487 | 680 { |
681 GaimConnection *gc = gaim_account_get_connection(account); | |
682 RendezvousData *rd; | |
683 | |
684 rd = g_new0(RendezvousData, 1); | |
685 rd->buddies = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, rendezvous_buddy_free); | |
686 gc->proto_data = rd; | |
687 | |
688 gaim_connection_update_progress(gc, _("Preparing Buddy List"), 0, RENDEZVOUS_CONNECT_STEPS); | |
689 rendezvous_removeallfromlocal(gc); | |
690 | |
10321 | 691 rd->listener = gaim_network_listen_range(5298, 5308); |
692 if (rd->listener == -1) { | |
693 gaim_connection_error(gc, _("Unable to establish listening port.")); | |
694 return; | |
695 } | |
696 rd->listener_watcher = gaim_input_add(rd->listener, GAIM_INPUT_READ, rendezvous_direct_acceptconnection, gc); | |
697 rd->listener_port = gaim_network_get_port_from_fd(rd->listener); | |
698 | |
8487 | 699 gaim_connection_update_progress(gc, _("Connecting"), 1, RENDEZVOUS_CONNECT_STEPS); |
8834 | 700 rd->fd = mdns_socket_establish(); |
8487 | 701 if (rd->fd == -1) { |
10321 | 702 gaim_connection_error(gc, _("Unable to establish mDNS socket.")); |
8487 | 703 return; |
704 } | |
705 | |
10596 | 706 /* |
707 * Watch our listening multicast UDP socket for incoming DNS | |
708 * packets. | |
709 */ | |
8487 | 710 gc->inpa = gaim_input_add(rd->fd, GAIM_INPUT_READ, rendezvous_callback, gc); |
10596 | 711 |
8487 | 712 gaim_connection_set_state(gc, GAIM_CONNECTED); |
713 | |
8636 | 714 mdns_query(rd->fd, "_presence._tcp.local", RENDEZVOUS_RRTYPE_ALL); |
8629 | 715 rendezvous_send_online(gc); |
8487 | 716 } |
717 | |
10321 | 718 static void |
719 rendezvous_prpl_close(GaimConnection *gc) | |
8487 | 720 { |
721 RendezvousData *rd = (RendezvousData *)gc->proto_data; | |
8631 | 722 ResourceRecordRDataTXTNode *node; |
8487 | 723 |
10596 | 724 rendezvous_send_offline(gc); |
725 | |
8487 | 726 if (gc->inpa) |
727 gaim_input_remove(gc->inpa); | |
728 | |
729 rendezvous_removeallfromlocal(gc); | |
730 | |
10321 | 731 if (rd == NULL) |
8487 | 732 return; |
733 | |
8834 | 734 mdns_socket_close(rd->fd); |
8487 | 735 |
10321 | 736 if (rd->listener >= 0) |
737 close(rd->listener); | |
738 | |
739 if (rd->listener_watcher != 0) | |
740 gaim_input_remove(rd->listener_watcher); | |
741 | |
8487 | 742 g_hash_table_destroy(rd->buddies); |
743 | |
8629 | 744 while (rd->mytxtdata != NULL) { |
745 node = rd->mytxtdata->data; | |
746 rd->mytxtdata = g_slist_remove(rd->mytxtdata, node); | |
747 g_free(node->name); | |
748 g_free(node->value); | |
749 g_free(node); | |
750 } | |
751 | |
8487 | 752 g_free(rd); |
753 } | |
754 | |
10321 | 755 static int |
756 rendezvous_prpl_send_im(GaimConnection *gc, const char *who, const char *message, GaimConvImFlags flags) | |
8487 | 757 { |
758 gaim_debug_info("rendezvous", "Sending IM\n"); | |
759 | |
10596 | 760 /* |
761 * TODO: Need to interpret any GaimConvImFlags here, before | |
762 * calling rendezvous_direct_send_message(). | |
763 */ | |
764 rendezvous_direct_send_message(gc, who, message); | |
10549 | 765 |
8487 | 766 return 1; |
767 } | |
768 | |
10321 | 769 static void |
770 rendezvous_prpl_set_status(GaimAccount *account, GaimStatus *status) | |
771 { | |
772 gaim_debug_error("rendezvous", "Set status to %s\n", gaim_status_get_name(status)); | |
773 } | |
774 | |
8487 | 775 static GaimPlugin *my_protocol = NULL; |
776 | |
8842 | 777 static GaimPluginProtocolInfo prpl_info; |
8487 | 778 |
779 static GaimPluginInfo info = | |
780 { | |
9954 | 781 GAIM_PLUGIN_MAGIC, |
782 GAIM_MAJOR_VERSION, | |
783 GAIM_MINOR_VERSION, | |
8487 | 784 GAIM_PLUGIN_PROTOCOL, /**< type */ |
785 NULL, /**< ui_requirement */ | |
786 0, /**< flags */ | |
787 NULL, /**< dependencies */ | |
788 GAIM_PRIORITY_DEFAULT, /**< priority */ | |
789 | |
790 "prpl-rendezvous", /**< id */ | |
791 "Rendezvous", /**< name */ | |
792 VERSION, /**< version */ | |
793 /** summary */ | |
794 N_("Rendezvous Protocol Plugin"), | |
795 /** description */ | |
796 N_("Rendezvous Protocol Plugin"), | |
797 NULL, /**< author */ | |
798 GAIM_WEBSITE, /**< homepage */ | |
799 | |
800 NULL, /**< load */ | |
801 NULL, /**< unload */ | |
802 NULL, /**< destroy */ | |
803 | |
804 NULL, /**< ui_info */ | |
8993 | 805 &prpl_info, /**< extra_info */ |
806 NULL, | |
807 NULL | |
8487 | 808 }; |
809 | |
810 static void init_plugin(GaimPlugin *plugin) | |
811 { | |
812 GaimAccountUserSplit *split; | |
813 GaimAccountOption *option; | |
8631 | 814 char hostname[255]; |
815 | |
9318 | 816 prpl_info.options = OPT_PROTO_NO_PASSWORD; |
817 prpl_info.icon_spec.format = "jpeg"; | |
818 prpl_info.icon_spec.min_width = 0; | |
819 prpl_info.icon_spec.min_height = 0; | |
820 prpl_info.icon_spec.max_width = 0; | |
821 prpl_info.icon_spec.max_height = 0; | |
9394 | 822 prpl_info.icon_spec.scale_rules = 0; |
9318 | 823 prpl_info.list_icon = rendezvous_prpl_list_icon; |
824 prpl_info.list_emblems = rendezvous_prpl_list_emblems; | |
825 prpl_info.status_text = rendezvous_prpl_status_text; | |
826 prpl_info.tooltip_text = rendezvous_prpl_tooltip_text; | |
10549 | 827 prpl_info.status_types = rendezvous_prpl_status_types; |
9318 | 828 prpl_info.login = rendezvous_prpl_login; |
829 prpl_info.close = rendezvous_prpl_close; | |
830 prpl_info.send_im = rendezvous_prpl_send_im; | |
10321 | 831 prpl_info.set_status = rendezvous_prpl_set_status; |
8842 | 832 |
8631 | 833 if (gethostname(hostname, 255) != 0) { |
10812
d087e928ffd1
[gaim-migrate @ 12465]
Luke Schierer <lschiere@pidgin.im>
parents:
10719
diff
changeset
|
834 gaim_debug_warning("rendezvous", "Error %d when getting host name. Using \"localhost.\"\n", errno); |
8631 | 835 strcpy(hostname, "localhost"); |
836 } | |
8487 | 837 |
838 /* Try to avoid making this configurable... */ | |
8842 | 839 split = gaim_account_user_split_new(_("Host name"), hostname, '@'); |
8487 | 840 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); |
841 | |
8842 | 842 option = gaim_account_option_string_new(_("First name"), "first", "Gaim"); |
8487 | 843 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, |
844 option); | |
845 | |
8842 | 846 option = gaim_account_option_string_new(_("Last name"), "last", _("User")); |
8487 | 847 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, |
848 option); | |
849 | |
8631 | 850 option = gaim_account_option_bool_new(_("Share AIM screen name"), "shareaim", FALSE); |
8487 | 851 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, |
852 option); | |
853 | |
854 my_protocol = plugin; | |
855 } | |
856 | |
857 GAIM_INIT_PLUGIN(rendezvous, init_plugin, info); |