Mercurial > pidgin
annotate src/protocols/rendezvous/rendezvous.c @ 10563:3e2cd3fe8897
[gaim-migrate @ 11944]
Fix a problem Justin Wood noticed and supplied sf patch 920581 to fix
My fix is slightly difference.
The problem was that, if an iChat user had an available message up,
then they changed their buddy icon, Gaim would stop showing the
available message for the person.
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Doliner <mark@kingant.net> |
|---|---|
| date | Tue, 01 Feb 2005 05:19:27 +0000 |
| parents | 8bc7ba019e96 |
| children | 0f7452b1f777 |
| 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" | |
| 28 #include "debug.h" | |
| 8834 | 29 #include "network.h" |
| 8487 | 30 #include "prpl.h" |
| 9416 | 31 #include "sha.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 | |
| 126 RendezvousBuddy *rb; | |
| 10549 | 127 rb = rendezvous_find_or_create_rendezvousbuddy(gc, name); |
| 8612 | 128 rb->ttltimer = gaim_timeout_add(time * 10000, rendezvous_buddy_timeout, gc); |
| 129 | |
| 130 gaim_timeout_remove(rb->ttltimer); | |
| 131 rb->ttltimer = 0; | |
| 132 #endif | |
| 8487 | 133 } |
| 134 | |
| 10321 | 135 static void |
| 136 rendezvous_removefromlocal(GaimConnection *gc, const char *name, const char *domain) | |
| 8487 | 137 { |
| 138 GaimAccount *account = gaim_connection_get_account(gc); | |
| 139 GaimBuddy *b; | |
| 140 GaimGroup *g; | |
| 141 | |
| 142 g = gaim_find_group(domain); | |
| 143 if (g == NULL) | |
| 144 return; | |
| 145 | |
| 146 b = gaim_find_buddy_in_group(account, name, g); | |
| 147 if (b == NULL) | |
| 148 return; | |
| 149 | |
| 10009 | 150 gaim_prpl_got_user_status(account, b->name, "offline", NULL); |
| 8487 | 151 gaim_blist_remove_buddy(b); |
| 8546 | 152 /* XXX - This results in incorrect group counts--needs to be fixed in the core */ |
| 10320 | 153 /* XXX - We also need to call remove_idle_buddy() in server.c for idle buddies */ |
| 8612 | 154 |
| 155 /* | |
| 156 * XXX - Instead of removing immediately, wait 10 seconds and THEN remove | |
| 157 * them. If you do it immediately you don't see the door close icon. | |
| 158 */ | |
| 8487 | 159 } |
| 160 | |
| 10321 | 161 static void |
| 162 rendezvous_removeallfromlocal(GaimConnection *gc) | |
| 8487 | 163 { |
| 164 GaimAccount *account = gaim_connection_get_account(gc); | |
| 165 GaimBuddyList *blist; | |
| 166 GaimBlistNode *gnode, *cnode, *bnode; | |
| 167 GaimBuddy *b; | |
| 168 | |
| 169 /* Go through and remove all buddies that belong to this account */ | |
| 170 if ((blist = gaim_get_blist()) != NULL) { | |
| 171 for (gnode = blist->root; gnode; gnode = gnode->next) { | |
| 172 if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
| 173 continue; | |
| 174 for (cnode = gnode->child; cnode; cnode = cnode->next) { | |
| 175 if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) | |
| 176 continue; | |
| 177 for (bnode = cnode->child; bnode; bnode = bnode->next) { | |
| 178 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode)) | |
| 179 continue; | |
| 180 b = (GaimBuddy *)bnode; | |
| 181 if (b->account != account) | |
| 182 continue; | |
| 10009 | 183 gaim_prpl_got_user_status(account, b->name, "offline", NULL); |
| 8487 | 184 gaim_blist_remove_buddy(b); |
| 185 } | |
| 186 } | |
| 187 } | |
| 188 } | |
| 189 } | |
| 190 | |
| 10321 | 191 static void |
| 192 rendezvous_handle_rr_a(GaimConnection *gc, ResourceRecord *rr, const gchar *name) | |
| 8834 | 193 { |
| 194 RendezvousBuddy *rb; | |
| 195 ResourceRecordRDataSRV *rdata; | |
| 196 | |
| 197 rdata = rr->rdata; | |
| 198 | |
| 10549 | 199 rb = rendezvous_find_or_create_rendezvousbuddy(gc, name); |
| 8834 | 200 |
| 10549 | 201 memcpy(rb->ipv4, rdata, 4); |
| 8834 | 202 } |
| 203 | |
| 10321 | 204 static void |
| 205 rendezvous_handle_rr_txt(GaimConnection *gc, ResourceRecord *rr, const gchar *name) | |
| 8487 | 206 { |
| 10011 | 207 GaimAccount *account = gaim_connection_get_account(gc); |
| 8487 | 208 RendezvousBuddy *rb; |
| 8806 | 209 GSList *rdata; |
| 210 ResourceRecordRDataTXTNode *node1, *node2; | |
| 8487 | 211 |
| 8594 | 212 rdata = rr->rdata; |
| 213 | |
| 214 /* Don't do a damn thing if the version is greater than 1 */ | |
| 8806 | 215 node1 = mdns_txt_find(rdata, "version"); |
| 216 if ((node1 == NULL) || (node1->value == NULL) || (strcmp(node1->value, "1"))) | |
| 8594 | 217 return; |
| 218 | |
| 10549 | 219 rb = rendezvous_find_or_create_rendezvousbuddy(gc, name); |
| 8487 | 220 |
| 8806 | 221 node1 = mdns_txt_find(rdata, "1st"); |
| 222 node2 = mdns_txt_find(rdata, "last"); | |
| 8487 | 223 g_free(rb->firstandlast); |
| 224 rb->firstandlast = g_strdup_printf("%s%s%s", | |
| 8806 | 225 (node1 && node1->value ? node1->value : ""), |
| 226 (node1 && node1->value && node2 && node2->value ? " " : ""), | |
| 227 (node2 && node2->value ? node2->value : "")); | |
| 8487 | 228 serv_got_alias(gc, name, rb->firstandlast); |
| 229 | |
| 8806 | 230 node1 = mdns_txt_find(rdata, "aim"); |
| 231 if ((node1 != NULL) && (node1->value != NULL)) { | |
| 8487 | 232 g_free(rb->aim); |
| 8806 | 233 rb->aim = g_strdup(node1->value); |
| 8487 | 234 } |
| 235 | |
| 8594 | 236 /* |
| 237 * We only want to use this port as a back-up. Ideally the port | |
| 238 * is specified in a separate, SRV resource record. | |
| 239 */ | |
| 240 if (rb->p2pjport == 0) { | |
| 8806 | 241 node1 = mdns_txt_find(rdata, "port.p2pj"); |
| 242 if ((node1 != NULL) && (node1->value)) | |
| 243 rb->p2pjport = atoi(node1->value); | |
| 8594 | 244 } |
| 8487 | 245 |
| 9775 | 246 node1 = mdns_txt_find(rdata, "status"); |
| 8806 | 247 if ((node1 != NULL) && (node1->value != NULL)) { |
| 248 if (!strcmp(node1->value, "avail")) { | |
| 8487 | 249 /* Available */ |
| 250 rb->status = 0; | |
| 8806 | 251 } else if (!strcmp(node1->value, "away")) { |
| 8487 | 252 /* Idle */ |
| 8806 | 253 node2 = mdns_txt_find(rdata, "away"); |
| 254 if ((node2 != NULL) && (node2->value)) { | |
| 9289 | 255 /* Time is seconds since January 1st 2001 GMT */ |
| 8806 | 256 rb->idle = atoi(node2->value); |
| 9289 | 257 rb->idle += 978307200; /* convert to seconds-since-epoch */ |
| 8806 | 258 } |
| 8487 | 259 rb->status = UC_IDLE; |
| 10549 | 260 /* TODO: Do this when the user is added to the buddy list? Definitely not here! */ |
| 261 /* gaim_prpl_got_user_idle(account, name, TRUE, rb->idle); */ | |
| 8806 | 262 } else if (!strcmp(node1->value, "dnd")) { |
| 8487 | 263 /* Away */ |
| 264 rb->status = UC_UNAVAILABLE; | |
| 265 } | |
| 10011 | 266 gaim_prpl_got_user_status(account, name, "online", NULL); |
| 9965 | 267 /* XXX - Idle time is rb->idle and status is rb->status */ |
| 8487 | 268 } |
| 269 | |
| 8806 | 270 node1 = mdns_txt_find(rdata, "msg"); |
| 271 if ((node1 != NULL) && (node1->value != NULL)) { | |
| 8487 | 272 g_free(rb->msg); |
| 8806 | 273 rb->msg = g_strdup(node1->value); |
| 8487 | 274 } |
| 8594 | 275 } |
| 8546 | 276 |
| 10321 | 277 static void |
| 278 rendezvous_handle_rr_aaaa(GaimConnection *gc, ResourceRecord *rr, const gchar *name) | |
| 279 { | |
| 280 RendezvousBuddy *rb; | |
| 281 ResourceRecordRDataSRV *rdata; | |
| 282 | |
| 283 rdata = rr->rdata; | |
| 284 | |
| 10549 | 285 rb = rendezvous_find_or_create_rendezvousbuddy(gc, name); |
| 10321 | 286 |
| 10549 | 287 memcpy(rb->ipv6, rdata, 16); |
| 10321 | 288 } |
| 289 | |
| 290 static void | |
| 291 rendezvous_handle_rr_srv(GaimConnection *gc, ResourceRecord *rr, const gchar *name) | |
| 8594 | 292 { |
| 293 RendezvousBuddy *rb; | |
| 8806 | 294 ResourceRecordRDataSRV *rdata; |
| 8594 | 295 |
| 296 rdata = rr->rdata; | |
| 297 | |
| 10549 | 298 rb = rendezvous_find_or_create_rendezvousbuddy(gc, name); |
| 8594 | 299 |
| 300 rb->p2pjport = rdata->port; | |
| 8487 | 301 } |
| 302 | |
| 303 /* | |
| 304 * Parse a resource record and do stuff if we need to. | |
| 305 */ | |
| 10321 | 306 static void |
| 307 rendezvous_handle_rr(GaimConnection *gc, ResourceRecord *rr) | |
| 8487 | 308 { |
| 8636 | 309 RendezvousData *rd = gc->proto_data; |
| 8487 | 310 gchar *name; |
| 311 | |
| 10321 | 312 gaim_debug_misc("rendezvous", "Parsing resource record with domain name %s and type %d\n", rr->name, rr->type); |
| 8594 | 313 |
| 8834 | 314 switch (rr->type) { |
| 315 case RENDEZVOUS_RRTYPE_A: { | |
| 316 name = rendezvous_extract_name(rr->name); | |
| 317 if (name != NULL) { | |
| 318 rendezvous_handle_rr_a(gc, rr, name); | |
| 319 g_free(name); | |
| 320 } | |
| 321 } break; | |
| 8487 | 322 |
| 323 case RENDEZVOUS_RRTYPE_NULL: { | |
| 8834 | 324 name = rendezvous_extract_name(rr->name); |
| 325 if (name != NULL) { | |
| 8487 | 326 if (rr->rdlength > 0) { |
| 327 /* Data is a buddy icon */ | |
| 328 gaim_buddy_icons_set_for_user(gaim_connection_get_account(gc), name, rr->rdata, rr->rdlength); | |
| 329 } | |
| 330 | |
| 331 g_free(name); | |
| 332 } | |
| 333 } break; | |
| 334 | |
| 335 case RENDEZVOUS_RRTYPE_PTR: { | |
| 336 gchar *rdata = rr->rdata; | |
| 8834 | 337 |
| 338 name = rendezvous_extract_name(rdata); | |
| 339 if (name != NULL) { | |
| 8636 | 340 if (rr->ttl > 0) { |
| 341 /* Add them to our buddy list and request their icon */ | |
| 8487 | 342 rendezvous_addtolocal(gc, name, "Rendezvous"); |
| 8636 | 343 mdns_query(rd->fd, rdata, RENDEZVOUS_RRTYPE_NULL); |
| 344 } else { | |
| 345 /* Remove them from our buddy list */ | |
| 8487 | 346 rendezvous_removefromlocal(gc, name, "Rendezvous"); |
| 8636 | 347 } |
| 8487 | 348 g_free(name); |
| 349 } | |
| 350 } break; | |
| 351 | |
| 352 case RENDEZVOUS_RRTYPE_TXT: { | |
| 8834 | 353 name = rendezvous_extract_name(rr->name); |
| 354 if (name != NULL) { | |
| 8487 | 355 rendezvous_handle_rr_txt(gc, rr, name); |
| 356 g_free(name); | |
| 357 } | |
| 358 } break; | |
| 8594 | 359 |
| 10321 | 360 case RENDEZVOUS_RRTYPE_AAAA: { |
| 361 name = rendezvous_extract_name(rr->name); | |
| 362 if (name != NULL) { | |
| 363 rendezvous_handle_rr_aaaa(gc, rr, name); | |
| 364 g_free(name); | |
| 365 } | |
| 366 } break; | |
| 367 | |
| 8594 | 368 case RENDEZVOUS_RRTYPE_SRV: { |
| 8834 | 369 name = rendezvous_extract_name(rr->name); |
| 370 if (name != NULL) { | |
| 8594 | 371 rendezvous_handle_rr_srv(gc, rr, name); |
| 372 g_free(name); | |
| 373 } | |
| 374 } break; | |
| 8487 | 375 } |
| 376 } | |
| 377 | |
| 378 /****************************/ | |
|
8735
92cbf9713795
[gaim-migrate @ 9490]
Christian Hammond <chipx86@chipx86.com>
parents:
8721
diff
changeset
|
379 /* Icon and Emblem Functions */ |
| 8487 | 380 /****************************/ |
| 10321 | 381 static const char * |
| 382 rendezvous_prpl_list_icon(GaimAccount *a, GaimBuddy *b) | |
| 8487 | 383 { |
| 384 return "rendezvous"; | |
| 385 } | |
| 386 | |
| 10321 | 387 static void |
| 388 rendezvous_prpl_list_emblems(GaimBuddy *b, const char **se, const char **sw, const char **nw, const char **ne) | |
| 8487 | 389 { |
| 390 if (GAIM_BUDDY_IS_ONLINE(b)) { | |
| 391 if (b->uc & UC_UNAVAILABLE) | |
| 392 *se = "away"; | |
| 393 } else { | |
| 394 *se = "offline"; | |
| 395 } | |
| 396 } | |
| 397 | |
| 10321 | 398 static gchar * |
| 399 rendezvous_prpl_status_text(GaimBuddy *b) | |
| 8487 | 400 { |
| 401 GaimConnection *gc = b->account->gc; | |
| 402 RendezvousData *rd = gc->proto_data; | |
| 403 RendezvousBuddy *rb; | |
| 404 gchar *ret; | |
| 405 | |
| 406 rb = g_hash_table_lookup(rd->buddies, b->name); | |
| 407 if ((rb == NULL) || (rb->msg == NULL)) | |
| 408 return NULL; | |
| 409 | |
| 410 ret = g_strdup(rb->msg); | |
| 411 | |
| 412 return ret; | |
| 413 } | |
| 414 | |
| 10321 | 415 static gchar * |
| 416 rendezvous_prpl_tooltip_text(GaimBuddy *b) | |
| 8487 | 417 { |
| 418 GaimConnection *gc = b->account->gc; | |
| 419 RendezvousData *rd = gc->proto_data; | |
| 420 RendezvousBuddy *rb; | |
| 421 GString *ret; | |
| 422 | |
| 423 rb = g_hash_table_lookup(rd->buddies, b->name); | |
| 424 if (rb == NULL) | |
| 425 return NULL; | |
| 426 | |
| 427 ret = g_string_new(""); | |
| 428 | |
| 429 if (rb->aim != NULL) | |
| 8591 | 430 g_string_append_printf(ret, "\n<b>%s</b>: %s", _("AIM Screen name"), rb->aim); |
| 8487 | 431 |
| 432 if (rb->msg != NULL) { | |
| 433 if (rb->status == UC_UNAVAILABLE) | |
| 8591 | 434 g_string_append_printf(ret, "\n<b>%s</b>: %s", _("Away"), rb->msg); |
| 8487 | 435 else |
| 8591 | 436 g_string_append_printf(ret, "\n<b>%s</b>: %s", _("Available"), rb->msg); |
| 8487 | 437 } |
| 438 | |
| 439 return g_string_free(ret, FALSE); | |
| 440 } | |
| 441 | |
| 10549 | 442 static GList * |
| 443 rendezvous_prpl_status_types(GaimAccount *account) | |
| 444 { | |
| 445 GList *status_types = NULL; | |
| 446 GaimStatusType *type; | |
| 447 | |
| 448 type = gaim_status_type_new_full(GAIM_STATUS_OFFLINE, "offline", _("Offline"), FALSE, TRUE, FALSE); | |
| 449 status_types = g_list_append(status_types, type); | |
| 450 | |
| 451 type = gaim_status_type_new_full(GAIM_STATUS_ONLINE, "online", _("Online"), FALSE, TRUE, FALSE); | |
| 452 status_types = g_list_append(status_types, type); | |
| 453 | |
| 454 return status_types; | |
| 455 } | |
| 456 | |
| 8487 | 457 /****************************/ |
|
8735
92cbf9713795
[gaim-migrate @ 9490]
Christian Hammond <chipx86@chipx86.com>
parents:
8721
diff
changeset
|
458 /* Connection Functions */ |
| 8487 | 459 /****************************/ |
| 10321 | 460 static void |
| 461 rendezvous_callback(gpointer data, gint source, GaimInputCondition condition) | |
| 8487 | 462 { |
| 463 GaimConnection *gc = data; | |
| 464 RendezvousData *rd = gc->proto_data; | |
| 465 DNSPacket *dns; | |
| 8806 | 466 GSList *cur; |
| 8487 | 467 |
| 468 gaim_debug_misc("rendezvous", "Received rendezvous datagram\n"); | |
| 469 | |
| 470 dns = mdns_read(rd->fd); | |
| 471 if (dns == NULL) | |
| 472 return; | |
| 473 | |
| 474 /* Handle the DNS packet */ | |
| 8806 | 475 for (cur = dns->answers; cur != NULL; cur = cur->next) |
| 476 rendezvous_handle_rr(gc, cur->data); | |
| 477 for (cur = dns->authority; cur != NULL; cur = cur->next) | |
| 478 rendezvous_handle_rr(gc, cur->data); | |
| 479 for (cur = dns->additional; cur != NULL; cur = cur->next) | |
| 480 rendezvous_handle_rr(gc, cur->data); | |
| 8487 | 481 |
| 482 mdns_free(dns); | |
| 483 } | |
| 484 | |
| 10321 | 485 static void |
| 486 rendezvous_add_to_txt(RendezvousData *rd, const char *name, const char *value) | |
| 8629 | 487 { |
| 8631 | 488 ResourceRecordRDataTXTNode *node; |
| 489 node = g_malloc(sizeof(ResourceRecordRDataTXTNode)); | |
| 8629 | 490 node->name = g_strdup(name); |
| 491 node->value = value != NULL ? g_strdup(value) : NULL; | |
| 492 rd->mytxtdata = g_slist_append(rd->mytxtdata, node); | |
| 493 } | |
| 494 | |
| 10321 | 495 static guchar * |
| 496 rendezvous_read_icon_data(const char *filename, unsigned short *length) | |
| 9416 | 497 { |
| 498 struct stat st; | |
| 499 FILE *file; | |
| 500 guchar *data; | |
| 501 | |
| 502 *length = 0; | |
| 503 | |
| 504 g_return_val_if_fail(filename != NULL, NULL); | |
| 505 | |
| 506 if (stat(filename, &st)) | |
| 507 return NULL; | |
| 508 | |
| 509 if (!(file = fopen(filename, "rb"))) | |
| 510 return NULL; | |
| 511 | |
| 512 *length = st.st_size; | |
| 513 data = g_malloc(*length); | |
| 514 fread(data, 1, *length, file); | |
| 515 fclose(file); | |
| 516 | |
| 517 return data; | |
| 518 } | |
| 519 | |
| 10321 | 520 static void |
| 521 rendezvous_add_to_txt_iconhash(RendezvousData *rd, const char *iconfile) | |
| 9416 | 522 { |
| 523 guchar *icondata; | |
| 524 unsigned short iconlength; | |
| 525 unsigned char hash[20]; | |
| 526 gchar *base16; | |
| 527 | |
| 528 g_return_if_fail(rd != NULL); | |
| 529 | |
| 530 if (iconfile == NULL) | |
| 531 return; | |
| 532 | |
| 533 icondata = rendezvous_read_icon_data(iconfile, &iconlength); | |
| 534 shaBlock((unsigned char *)icondata, iconlength, hash); | |
| 535 g_free(icondata); | |
| 536 | |
| 537 base16 = gaim_base16_encode(hash, 20); | |
| 538 rendezvous_add_to_txt(rd, "phsh", base16); | |
| 539 g_free(base16); | |
| 540 } | |
| 541 | |
| 10321 | 542 static void |
| 543 rendezvous_send_icon(GaimConnection *gc) | |
| 8636 | 544 { |
| 545 RendezvousData *rd = gc->proto_data; | |
| 546 GaimAccount *account = gaim_connection_get_account(gc); | |
| 547 const char *iconfile = gaim_account_get_buddy_icon(account); | |
| 548 unsigned char *rdata; | |
| 549 unsigned short rdlength; | |
| 550 gchar *myname; | |
| 551 | |
| 552 if (iconfile == NULL) | |
| 553 return; | |
| 554 | |
| 9416 | 555 rdata = rendezvous_read_icon_data(iconfile, &rdlength); |
| 8636 | 556 |
| 557 myname = g_strdup_printf("%s._presence._tcp.local", gaim_account_get_username(account)); | |
| 558 mdns_advertise_null(rd->fd, myname, rdata, rdlength); | |
| 559 g_free(myname); | |
| 8695 | 560 |
| 561 g_free(rdata); | |
| 8636 | 562 } |
| 563 | |
| 10321 | 564 static void |
| 565 rendezvous_send_online(GaimConnection *gc) | |
| 8629 | 566 { |
| 567 RendezvousData *rd = gc->proto_data; | |
| 568 GaimAccount *account = gaim_connection_get_account(gc); | |
| 10549 | 569 const gchar *me, *myip; |
| 10321 | 570 gchar *myname, *mycomp, *myport; |
| 10549 | 571 gchar **mysplitip; |
| 10321 | 572 unsigned char myipv4[4]; |
| 8629 | 573 |
| 8631 | 574 me = gaim_account_get_username(account); |
| 575 myname = g_strdup_printf("%s._presence._tcp.local", me); | |
| 576 mycomp = g_strdup_printf("%s.local", strchr(me, '@') + 1); | |
| 10321 | 577 myport = g_strdup_printf("%d", rd->listener_port); |
| 8631 | 578 |
| 10549 | 579 myip = gaim_network_get_local_system_ip(-1); |
| 580 mysplitip = g_strsplit(myip, ".", 0); | |
| 581 myipv4[0] = atoi(mysplitip[0]); | |
| 582 myipv4[1] = atoi(mysplitip[1]); | |
| 583 myipv4[2] = atoi(mysplitip[2]); | |
| 584 myipv4[3] = atoi(mysplitip[3]); | |
| 585 g_strfreev(mysplitip); | |
| 586 | |
| 10321 | 587 mdns_advertise_a(rd->fd, mycomp, myipv4); |
| 8631 | 588 mdns_advertise_ptr(rd->fd, "_presence._tcp.local", myname); |
| 10321 | 589 mdns_advertise_srv(rd->fd, myname, rd->listener_port, mycomp); |
| 8629 | 590 |
| 591 rendezvous_add_to_txt(rd, "txtvers", "1"); | |
| 592 rendezvous_add_to_txt(rd, "status", "avail"); | |
| 8631 | 593 /* rendezvous_add_to_txt(rd, "vc", "A!"); */ |
| 9416 | 594 rendezvous_add_to_txt_iconhash(rd, gaim_account_get_buddy_icon(account)); |
| 8629 | 595 rendezvous_add_to_txt(rd, "1st", gaim_account_get_string(account, "first", "Gaim")); |
| 8631 | 596 if (gaim_account_get_bool(account, "shareaim", FALSE)) { |
| 597 GList *l; | |
| 598 GaimAccount *cur; | |
| 599 for (l = gaim_accounts_get_all(); l != NULL; l = l->next) { | |
| 600 cur = (GaimAccount *)l->data; | |
| 601 if (!strcmp(gaim_account_get_protocol_id(cur), "prpl-oscar")) { | |
| 8634 | 602 /* XXX - Should the name be normalized? */ |
| 8631 | 603 rendezvous_add_to_txt(rd, "AIM", gaim_account_get_username(cur)); |
| 604 break; | |
| 605 } | |
| 606 } | |
| 607 } | |
| 8629 | 608 rendezvous_add_to_txt(rd, "version", "1"); |
| 8631 | 609 rendezvous_add_to_txt(rd, "msg", "Groovin'"); |
| 10321 | 610 rendezvous_add_to_txt(rd, "port.p2pj", myport); |
| 8629 | 611 rendezvous_add_to_txt(rd, "last", gaim_account_get_string(account, "last", _("User"))); |
| 8631 | 612 mdns_advertise_txt(rd->fd, myname, rd->mytxtdata); |
| 8629 | 613 |
| 8636 | 614 rendezvous_send_icon(gc); |
| 615 | |
| 8631 | 616 g_free(myname); |
| 617 g_free(mycomp); | |
| 10321 | 618 g_free(myport); |
| 8629 | 619 } |
| 620 | |
| 10321 | 621 static void |
| 10401 | 622 rendezvous_prpl_login(GaimAccount *account, GaimStatus *status) |
| 8487 | 623 { |
| 624 GaimConnection *gc = gaim_account_get_connection(account); | |
| 625 RendezvousData *rd; | |
| 626 | |
| 627 rd = g_new0(RendezvousData, 1); | |
| 628 rd->buddies = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, rendezvous_buddy_free); | |
| 629 gc->proto_data = rd; | |
| 630 | |
| 631 gaim_connection_update_progress(gc, _("Preparing Buddy List"), 0, RENDEZVOUS_CONNECT_STEPS); | |
| 632 rendezvous_removeallfromlocal(gc); | |
| 633 | |
| 10321 | 634 rd->listener = gaim_network_listen_range(5298, 5308); |
| 635 if (rd->listener == -1) { | |
| 636 gaim_connection_error(gc, _("Unable to establish listening port.")); | |
| 637 return; | |
| 638 } | |
| 639 rd->listener_watcher = gaim_input_add(rd->listener, GAIM_INPUT_READ, rendezvous_direct_acceptconnection, gc); | |
| 640 rd->listener_port = gaim_network_get_port_from_fd(rd->listener); | |
| 641 | |
| 8487 | 642 gaim_connection_update_progress(gc, _("Connecting"), 1, RENDEZVOUS_CONNECT_STEPS); |
| 8834 | 643 rd->fd = mdns_socket_establish(); |
| 8487 | 644 if (rd->fd == -1) { |
| 10321 | 645 gaim_connection_error(gc, _("Unable to establish mDNS socket.")); |
| 8487 | 646 return; |
| 647 } | |
| 648 | |
| 649 gc->inpa = gaim_input_add(rd->fd, GAIM_INPUT_READ, rendezvous_callback, gc); | |
| 650 gaim_connection_set_state(gc, GAIM_CONNECTED); | |
| 651 | |
| 8636 | 652 mdns_query(rd->fd, "_presence._tcp.local", RENDEZVOUS_RRTYPE_ALL); |
| 8629 | 653 rendezvous_send_online(gc); |
| 8487 | 654 } |
| 655 | |
| 10321 | 656 static void |
| 657 rendezvous_prpl_close(GaimConnection *gc) | |
| 8487 | 658 { |
| 659 RendezvousData *rd = (RendezvousData *)gc->proto_data; | |
| 8631 | 660 ResourceRecordRDataTXTNode *node; |
| 8487 | 661 |
| 662 if (gc->inpa) | |
| 663 gaim_input_remove(gc->inpa); | |
| 664 | |
| 665 rendezvous_removeallfromlocal(gc); | |
| 666 | |
| 10321 | 667 if (rd == NULL) |
| 8487 | 668 return; |
| 669 | |
| 8834 | 670 mdns_socket_close(rd->fd); |
| 8487 | 671 |
| 10321 | 672 if (rd->listener >= 0) |
| 673 close(rd->listener); | |
| 674 | |
| 675 if (rd->listener_watcher != 0) | |
| 676 gaim_input_remove(rd->listener_watcher); | |
| 677 | |
| 8487 | 678 g_hash_table_destroy(rd->buddies); |
| 679 | |
| 8629 | 680 while (rd->mytxtdata != NULL) { |
| 681 node = rd->mytxtdata->data; | |
| 682 rd->mytxtdata = g_slist_remove(rd->mytxtdata, node); | |
| 683 g_free(node->name); | |
| 684 g_free(node->value); | |
| 685 g_free(node); | |
| 686 } | |
| 687 | |
| 8487 | 688 g_free(rd); |
| 689 } | |
| 690 | |
| 10321 | 691 static int |
| 692 rendezvous_prpl_send_im(GaimConnection *gc, const char *who, const char *message, GaimConvImFlags flags) | |
| 8487 | 693 { |
| 10549 | 694 RendezvousData *rd = gc->proto_data; |
| 695 RendezvousBuddy *rb; | |
| 696 | |
| 8487 | 697 gaim_debug_info("rendezvous", "Sending IM\n"); |
| 698 | |
| 10549 | 699 rb = g_hash_table_lookup(rd->buddies, who); |
| 700 if (rb == NULL) { | |
| 701 /* TODO: Should print an error to the user, here */ | |
| 702 gaim_debug_error("rendezvous", "Could not send message to %s: Could not find user information.\n", who); | |
| 703 } | |
| 704 | |
| 705 /* TODO: Establish a direct connection then send IM. Will need to queue the message somewhere. */ | |
| 706 | |
| 8487 | 707 return 1; |
| 708 } | |
| 709 | |
| 10321 | 710 static void |
| 711 rendezvous_prpl_set_status(GaimAccount *account, GaimStatus *status) | |
| 712 { | |
| 713 gaim_debug_error("rendezvous", "Set status to %s\n", gaim_status_get_name(status)); | |
| 714 } | |
| 715 | |
| 8487 | 716 static GaimPlugin *my_protocol = NULL; |
| 717 | |
| 8842 | 718 static GaimPluginProtocolInfo prpl_info; |
| 8487 | 719 |
| 720 static GaimPluginInfo info = | |
| 721 { | |
| 9954 | 722 GAIM_PLUGIN_MAGIC, |
| 723 GAIM_MAJOR_VERSION, | |
| 724 GAIM_MINOR_VERSION, | |
| 8487 | 725 GAIM_PLUGIN_PROTOCOL, /**< type */ |
| 726 NULL, /**< ui_requirement */ | |
| 727 0, /**< flags */ | |
| 728 NULL, /**< dependencies */ | |
| 729 GAIM_PRIORITY_DEFAULT, /**< priority */ | |
| 730 | |
| 731 "prpl-rendezvous", /**< id */ | |
| 732 "Rendezvous", /**< name */ | |
| 733 VERSION, /**< version */ | |
| 734 /** summary */ | |
| 735 N_("Rendezvous Protocol Plugin"), | |
| 736 /** description */ | |
| 737 N_("Rendezvous Protocol Plugin"), | |
| 738 NULL, /**< author */ | |
| 739 GAIM_WEBSITE, /**< homepage */ | |
| 740 | |
| 741 NULL, /**< load */ | |
| 742 NULL, /**< unload */ | |
| 743 NULL, /**< destroy */ | |
| 744 | |
| 745 NULL, /**< ui_info */ | |
| 8993 | 746 &prpl_info, /**< extra_info */ |
| 747 NULL, | |
| 748 NULL | |
| 8487 | 749 }; |
| 750 | |
| 751 static void init_plugin(GaimPlugin *plugin) | |
| 752 { | |
| 753 GaimAccountUserSplit *split; | |
| 754 GaimAccountOption *option; | |
| 8631 | 755 char hostname[255]; |
| 756 | |
| 9318 | 757 prpl_info.options = OPT_PROTO_NO_PASSWORD; |
| 758 prpl_info.icon_spec.format = "jpeg"; | |
| 759 prpl_info.icon_spec.min_width = 0; | |
| 760 prpl_info.icon_spec.min_height = 0; | |
| 761 prpl_info.icon_spec.max_width = 0; | |
| 762 prpl_info.icon_spec.max_height = 0; | |
| 9394 | 763 prpl_info.icon_spec.scale_rules = 0; |
| 9318 | 764 prpl_info.list_icon = rendezvous_prpl_list_icon; |
| 765 prpl_info.list_emblems = rendezvous_prpl_list_emblems; | |
| 766 prpl_info.status_text = rendezvous_prpl_status_text; | |
| 767 prpl_info.tooltip_text = rendezvous_prpl_tooltip_text; | |
| 10549 | 768 prpl_info.status_types = rendezvous_prpl_status_types; |
| 9318 | 769 prpl_info.login = rendezvous_prpl_login; |
| 770 prpl_info.close = rendezvous_prpl_close; | |
| 771 prpl_info.send_im = rendezvous_prpl_send_im; | |
| 10321 | 772 prpl_info.set_status = rendezvous_prpl_set_status; |
| 8842 | 773 |
| 8631 | 774 if (gethostname(hostname, 255) != 0) { |
| 775 gaim_debug_warning("rendezvous", "Error %d when getting host name. Using \"localhost.\"\n", errno); | |
| 776 strcpy(hostname, "localhost"); | |
| 777 } | |
| 8487 | 778 |
| 779 /* Try to avoid making this configurable... */ | |
| 8842 | 780 split = gaim_account_user_split_new(_("Host name"), hostname, '@'); |
| 8487 | 781 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); |
| 782 | |
| 8842 | 783 option = gaim_account_option_string_new(_("First name"), "first", "Gaim"); |
| 8487 | 784 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, |
| 785 option); | |
| 786 | |
| 8842 | 787 option = gaim_account_option_string_new(_("Last name"), "last", _("User")); |
| 8487 | 788 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, |
| 789 option); | |
| 790 | |
| 8631 | 791 option = gaim_account_option_bool_new(_("Share AIM screen name"), "shareaim", FALSE); |
| 8487 | 792 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, |
| 793 option); | |
| 794 | |
| 795 my_protocol = plugin; | |
| 796 } | |
| 797 | |
| 798 GAIM_INIT_PLUGIN(rendezvous, init_plugin, info); |
