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