Changes in / [531eabd:b1dc403]
- Files:
-
- 3 added
- 3 deleted
- 49 edited
Legend:
- Unmodified
- Added
- Removed
-
.travis.yml
r531eabd rb1dc403 1 1 language: c 2 script: ./configure && make check && dpkg-buildpackage -uc -us 2 3 script: 4 - ./configure 5 - make check 6 - dpkg-buildpackage -uc -us 7 3 8 before_install: 4 9 - sudo apt-get update -qq … … 7 12 - sudo dpkg -i *.deb 8 13 14 env: 15 global: 16 # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created 17 # via the "travis encrypt" command using the project repo's public key 18 - secure: "MO6hy2cRxR02A0nSenfQFyPFpepxorJ+XgNkq2JS7LtI6tcwYRR0alvunIPJXam1/OUKxoFsBJLS1nCJTvEUXFCOvoTSAoMiePTBUEg2zfzcTb5k+cqtcOUznCXHNmXAwrqriP4vkG+57ijO9Ojz2r9LijcvjtFDRFJQY9Rcs38=" 19 20 addons: 21 coverity_scan: 22 project: 23 name: "bitlbee/bitlbee" 24 description: "An IRC to other chat networks gateway" 25 notification_email: dx@dxzone.com.ar 26 build_command_prepend: ./configure --otr=1 --debug=1 27 build_command: make 28 branch_pattern: coverity_scan 29 30 notifications: 31 email: false -
Makefile
r531eabd rb1dc403 25 25 26 26 doc: 27 ifdef DOC 27 28 $(MAKE) -C doc 29 endif 28 30 29 31 uninstall: uninstall-bin uninstall-doc … … 73 75 74 76 install-doc: 77 ifdef DOC 75 78 $(MAKE) -C doc install 79 endif 76 80 ifdef SKYPE_PI 77 81 $(MAKE) -C protocols/skype install-doc … … 79 83 80 84 uninstall-doc: 85 ifdef DOC 81 86 $(MAKE) -C doc uninstall 87 endif 82 88 ifdef SKYPE_PI 83 89 $(MAKE) -C protocols/skype uninstall-doc … … 153 159 x=$$(basename $$(pwd)); \ 154 160 cd ..; \ 155 tar czf $$x.tar.gz --exclude -from=.gitignore$$x161 tar czf $$x.tar.gz --exclude=debian --exclude=.git* --exclude=.depend $$x 156 162 157 163 $(subdirs): -
bitlbee.h
r531eabd rb1dc403 36 36 37 37 #define PACKAGE "BitlBee" 38 #define BITLBEE_VERSION "3. 2.2"38 #define BITLBEE_VERSION "3.4" 39 39 #define VERSION BITLBEE_VERSION 40 40 #define BITLBEE_VER(a, b, c) (((a) << 16) + ((b) << 8) + (c)) 41 #define BITLBEE_VERSION_CODE BITLBEE_VER(3, 2, 2)41 #define BITLBEE_VERSION_CODE BITLBEE_VER(3, 4, 0) 42 42 43 43 #define MAX_STRING 511 -
configure
r531eabd rb1dc403 38 38 purple=0 39 39 40 doc=1 40 41 debug=0 41 42 strip=1 … … 56 57 GLIB_MIN_VERSION=2.16 57 58 58 echo BitlBee configure59 60 59 # Cygwin and Darwin don't support PIC/PIE 61 60 case "$arch" in 62 63 64 65 61 CYGWIN* ) 62 pie=0;; 63 Darwin ) 64 pie=0;; 66 65 esac 66 67 get_version() { 68 REAL_BITLBEE_VERSION=$(grep '^#define BITLBEE_VERSION ' $srcdir/bitlbee.h | sed 's/.*\"\(.*\)\".*/\1/') 69 BITLBEE_VERSION=$REAL_BITLBEE_VERSION 70 71 if [ -d $srcdir/.git ] && type git > /dev/null 2> /dev/null; then 72 timestamp=$(cd $srcdir; git show -s --format=%ci HEAD | sed 's/ .*$//; s/-//g') 73 branch=$(cd $srcdir; git rev-parse --abbrev-ref HEAD) 74 75 search="(.+)-([0-9]+)-(g[0-9a-f]+)" 76 replace="\1+$timestamp+$branch+\2-\3-git" 77 78 BITLBEE_VERSION=$(cd $srcdir; git describe --long --tags | sed -r "s/$search/$replace/") 79 80 unset timestamp branch search replace 81 fi 82 } 83 84 if [ "$1" = "--dump-version" ]; then 85 srcdir=$(cd $(dirname $0);pwd) 86 get_version 87 echo $BITLBEE_VERSION 88 exit 89 fi 90 91 echo BitlBee configure 67 92 68 93 while [ -n "$1" ]; do … … 96 121 --rpc=0/1 Disable/enable RPC interface $rpc 97 122 123 --doc=0/1 Disable/enable help.txt generation $doc 98 124 --debug=0/1 Disable/enable debugging $debug 99 125 --strip=0/1 Disable/enable binary stripping $strip … … 450 476 ret=1 451 477 echo "$RESOLV_NS_TESTCODE" | $CC -o $TMPFILE -x c - $LIBRESOLV >/dev/null 2>/dev/null 452 453 454 478 if [ "$?" = "0" ]; then 479 ret=0 480 fi 455 481 456 482 rm -f $TMPFILE … … 465 491 if [ -f $i/libresolv.a ]; then 466 492 echo "$RESOLV_NS_TESTCODE" | $CC -o $TMPFILE -x c - -Wl,$i/libresolv.a >/dev/null 2>/dev/null 467 468 469 493 if [ "$?" = "0" ]; then 494 ret=0 495 fi 470 496 fi 471 497 done … … 477 503 detect_nameser_has_ns_types() 478 504 { 479 480 481 482 483 484 485 486 487 488 489 505 TMPFILE=$(mktemp /tmp/bitlbee-configure.XXXXXX) 506 ret=1 507 # since we aren't actually linking with ns_* routines 508 # we can just compile the test code 509 echo "$RESOLV_NS_TYPES_TESTCODE" | $CC -o $TMPFILE -x c - >/dev/null 2>/dev/null 510 if [ "$?" = "0" ]; then 511 ret=0 512 fi 513 514 rm -f $TMPFILE 515 return $ret 490 516 } 491 517 … … 548 574 if detect_resolv_dynamic || detect_resolv_static; then 549 575 echo '#define HAVE_RESOLV_A' >> config.h 550 551 552 553 else 554 576 if detect_resolv_ns_dynamic || detect_resolv_ns_static; then 577 echo '#define HAVE_RESOLV_A_WITH_NS' >> config.h 578 fi 579 else 580 echo 'Insufficient resolv routines. Jabber server must be set explicitly' 555 581 fi 556 582 … … 649 675 fi 650 676 651 if [ ! -e doc/user-guide/help.txt ] && ! type xmlto > /dev/null 2> /dev/null; then 652 echo 653 echo 'WARNING: Building from an unreleased source tree without prebuilt helpfile.' 654 echo 'Install xmlto if you want online help to work.' 655 fi 656 657 REAL_BITLBEE_VERSION=`grep '^#define BITLBEE_VERSION ' $srcdir/bitlbee.h | sed 's/.*\"\(.*\)\".*/\1/'` 658 echo 659 if [ -z "$BITLBEE_VERSION" -a -d .bzr ] && type bzr > /dev/null 2> /dev/null; then 660 nick=`bzr nick` 661 if [ -n "$nick" -a "$nick" != "bitlbee" ]; then 662 nick="-$nick" 677 if [ "$doc" = "1" ]; then 678 if [ ! -e doc/user-guide/help.txt ] && \ 679 ! type xmlto > /dev/null 2> /dev/null || \ 680 ! type xsltproc > /dev/null 2> /dev/null 681 then 682 echo 683 echo 'WARNING: Building from an unreleased source tree without prebuilt helpfile.' 684 echo 'Install xmlto and xsltproc if you want online help to work.' 663 685 else 664 nick="" 665 fi 666 rev=`bzr revno` 667 echo 'Using bzr revision #'$rev' as version number' 668 BITLBEE_VERSION=$REAL_BITLBEE_VERSION-bzr$nick-$rev 669 fi 670 671 if [ -z "$BITLBEE_VERSION" -a -d .git ] && type git > /dev/null 2> /dev/null; then 672 rev=`git describe --long --tags`-`git rev-parse --abbrev-ref HEAD` 673 echo 'Using '$rev' as git version number' 674 BITLBEE_VERSION=$rev-git 675 fi 676 677 if [ -n "$BITLBEE_VERSION" ]; then 686 echo "DOC=1" >> Makefile.settings 687 fi 688 689 if [ "$skype" = "1" -o "$skype" = "plugin" ]; then 690 # skype also needs asciidoc 691 if ! type a2x > /dev/null 2> /dev/null; then 692 echo 693 echo 'WARNING: The skyped man page requires asciidoc. It will not be generated.' 694 else 695 echo "ASCIIDOC=1" >> Makefile.settings 696 fi 697 fi 698 fi 699 700 get_version 701 702 if [ "$BITLBEE_VERSION" != "$REAL_BITLBEE_VERSION" ]; then 678 703 echo 'Spoofing version number: '$BITLBEE_VERSION 679 704 echo '#undef BITLBEE_VERSION' >> config.h 680 705 echo '#define BITLBEE_VERSION "'$BITLBEE_VERSION'"' >> config.h 681 706 echo 682 else683 # for pkg-config684 BITLBEE_VERSION=$REAL_BITLBEE_VERSION685 707 fi 686 708 -
doc/CHANGES
r531eabd rb1dc403 1 1 This ChangeLog mostly lists changes relevant to users. A full log can be 2 found in the bzr commit logs, for example you can try: 3 4 http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on 2 found in the git commit logs, for example you can try: 3 4 https://github.com/bitlbee/bitlbee/commits/master 5 6 Version 3.4: 7 - First release pretty much fully prepared by dx instead of Wilmer. Just look 8 at the tightly structured changelog! 9 - Main repository migrated from bzr to git 10 - Some API/ABI changes. Recompiling third party plugins is required! 11 - Important bugfixes: 12 * Fix memory leak when calling word_wrap() on groupchat messages (dx) 13 * Fix segfault after a file transfer is complete (dx) 14 * Fix bug where NSS would refuse to work in forkdaemon mode (dx) 15 * Fix several bugs with UTF8 nicks (dx) 16 * Fix some nasty deadlocks that appared mostly with libpurple (dx) 17 - General changes: 18 * Add a 'pattern' parameter to the blist command, to filter it (tribut) 19 * Implemented /kick support, only supported by purple for now (jgeboski) 20 * Add a "special" state to show_users (mapped to the % prefix) (jgeboski) 21 * Improved support for cygwin, openbsd and darwin (jcopenha) 22 * Create temporary users instead of showing "Message from unknown 23 participant" (jgeboski) 24 - purple: 25 * Local contact lists for gadugadu and whatsapp (dx) 26 * Add topic and name_hint to groupchats (seirl) 27 * Support for 'input' requests (such as telegram auth codes) (seirl) 28 Note that telegram-purple itself is rather unstable ATM, it may crash. 29 - jabber: 30 * Handle compressed DNS responses in SRV lookup (jcopenha) 31 * Fix case sensitivity issues with JIDs (GRMrGecko, dx) 32 * Implement XEP-0203 style message timestamps (dx) 33 * Fix "Server claims your JID is X instead of Y" warnings (dx) 34 * Account-wide display_name setting, mostly for hipchat (dx) 35 - twitter: 36 * Filter channels. Search by keyword/hashtag or a list of users (jgeboski) 37 * Fix bug in "reply" command which removed the first quote character (dx) 38 * Add "rawreply" command, like reply but bitlbee won't add @mention (WillP) 39 * Add support for The United States of America (favorite/fav aliases) (dx) 40 * Default show_old_mentions to 0 (dx) 41 * Start stream from last tweet on connect/reconnect (roger) 42 - msn: 43 * Disabled module by default. The protocol we used (MSNP18) stopped working 44 last week. This is being worked on, but it's far from ready for release. 45 - And lots of small bugfixes, too many to list here. 46 47 Finished 25 Mar 2015 5 48 6 49 Version 3.2.2: -
doc/user-guide/commands.xml
r531eabd rb1dc403 121 121 <description> 122 122 <para> 123 This command sdeletes an account from your account list. You should signoff the account before deleting it.123 This command deletes an account from your account list. You should signoff the account before deleting it. 124 124 </para> 125 125 … … 853 853 <varlistentry><term>favourite <screenname|#id></term><listitem><para>Favo<emphasis>u</emphasis>rite the given user's most recent tweet, or the given tweet ID.</para></listitem></varlistentry> 854 854 <varlistentry><term>post <message></term><listitem><para>Post a tweet</para></listitem></varlistentry> 855 <varlistentry><term>url <screenname|#id></term><listitem><para>Show URL for a tweet to open it in a browser (and see context)</para></listitem></varlistentry> 855 856 </variablelist> 856 857 -
doc/user-guide/misc.xml
r531eabd rb1dc403 409 409 </sect1> 410 410 411 <sect1 id="whatsnew030400"> 412 <title>New stuff in BitlBee 3.4</title> 413 414 <para> 415 Lots of bugfixes! <emphasis>Important:</emphasis> Recompiling third party plugins such as bitlbee-steam or bitlbee-facebook is <emphasis>required</emphasis>! 416 </para> 417 418 <simplelist> 419 <member><emphasis>twitter:</emphasis> Filter channels - Search by keyword/hashtag or a list of users. See the <emphasis>HowtoTwitter</emphasis> wiki page for more details!</member> 420 <member><emphasis>twitter:</emphasis> Add "rawreply" command, like reply but bitlbee won't add @mention. Also add "favorite" / "fav" command aliases.</member> 421 <member><emphasis>twitter:</emphasis> Start stream from last tweet on connect/reconnect to avoid showing duplicate tweets</member> 422 <member><emphasis>jabber:</emphasis> Fixed crashes with file transfers (they still fail at bypassing NATs, but at least they fail without crashing)</member> 423 <member><emphasis>purple:</emphasis> Improved support for gadugadu, whatsapp and telegram.</member> 424 <member><emphasis>msn:</emphasis> disabled in this release since the protocol we used (MSNP18) stopped working.</member> 425 <member>Add a 'pattern' parameter to the blist command, to filter it.</member> 426 <member>The <emphasis>utf8_nicks</emphasis> setting should be more reliable now.</member> 427 </simplelist> 428 429 <para> 430 See the full changelog for details! 431 </para> 432 433 </sect1> 434 411 435 </chapter> -
help.c
r531eabd rb1dc403 30 30 #undef write 31 31 32 #define BUFSIZE 110032 #define BUFSIZE 2048 33 33 34 34 help_t *help_init(help_t **help, const char *helpfile) -
ipc.c
r531eabd rb1dc403 776 776 } 777 777 778 child_list = g_slist_remove(child_list, c); 779 778 780 g_free(c->host); 779 781 g_free(c->nick); … … 781 783 g_free(c->password); 782 784 g_free(c); 783 784 child_list = g_slist_remove(child_list, c);785 785 786 786 /* Also, if any child has a reference to this one, remove it. */ -
irc.c
r531eabd rb1dc403 764 764 irc_rootmsg(irc, 765 765 "Welcome to the BitlBee gateway!\n\n" 766 "Running %s %s\n\n" 766 767 "If you've never used BitlBee before, please do read the help " 767 768 "information using the \x02help\x02 command. Lots of FAQs are " 768 769 "answered there.\n" 769 770 "If you already have an account on this server, just use the " 770 "\x02identify\x02 command to identify yourself."); 771 "\x02identify\x02 command to identify yourself.", 772 PACKAGE, BITLBEE_VERSION); 771 773 772 774 /* This is for bug #209 (use PASS to identify to NickServ). */ -
irc.h
r531eabd rb1dc403 299 299 void irc_channel_name_strip(char *name); 300 300 int irc_channel_name_cmp(const char *a_, const char *b_); 301 char *irc_channel_name_gen(irc_t *irc, const char *name); 302 gboolean irc_channel_name_hint(irc_channel_t *ic, const char *name); 301 303 void irc_channel_update_ops(irc_channel_t *ic, char *value); 302 304 char *set_eval_irc_channel_ops(struct set *set, char *value); -
irc_channel.c
r531eabd rb1dc403 556 556 } 557 557 558 gboolean irc_channel_is_unused(irc_t *irc, char *name) 559 { 560 char *type, *chat_type; 561 irc_channel_t *oic; 562 563 if (!irc_channel_name_ok(name)) { 564 return FALSE; 565 } 566 567 if (!(oic = irc_channel_by_name(irc, name))) { 568 return TRUE; 569 } 570 571 type = set_getstr(&oic->set, "type"); 572 chat_type = set_getstr(&oic->set, "chat_type"); 573 574 if (type && chat_type && oic->data == FALSE && 575 strcmp(type, "chat") == 0 && 576 strcmp(chat_type, "groupchat") == 0) { 577 /* There's a channel with this name already, but it looks 578 like it's not in use yet. Most likely the IRC client 579 rejoined the channel after a reconnect. Remove it so 580 we can reuse its name. */ 581 irc_channel_free(oic); 582 return TRUE; 583 } 584 585 return FALSE; 586 } 587 588 char *irc_channel_name_gen(irc_t *irc, const char *hint) 589 { 590 char name[MAX_NICK_LENGTH + 1] = { 0 }; 591 char *translit_name; 592 gsize bytes_written; 593 594 translit_name = g_convert_with_fallback(hint, -1, "ASCII//TRANSLIT", "UTF-8", "", NULL, &bytes_written, NULL); 595 if (bytes_written > MAX_NICK_LENGTH) { 596 translit_name[MAX_NICK_LENGTH] = '\0'; 597 } 598 599 name[0] = '#'; 600 strncpy(name + 1, translit_name, MAX_NICK_LENGTH - 1); 601 name[MAX_NICK_LENGTH] = '\0'; 602 603 g_free(translit_name); 604 605 irc_channel_name_strip(name); 606 607 if (set_getbool(&irc->b->set, "lcnicks")) { 608 nick_lc(irc, name + 1); 609 } 610 611 while (!irc_channel_is_unused(irc, name)) { 612 underscore_dedupe(name); 613 } 614 615 return g_strdup(name); 616 } 617 618 gboolean irc_channel_name_hint(irc_channel_t *ic, const char *name) 619 { 620 irc_t *irc = ic->irc; 621 char *full_name; 622 623 /* Don't rename a channel if the user's in it already. */ 624 if (ic->flags & IRC_CHANNEL_JOINED) { 625 return FALSE; 626 } 627 628 if (!(full_name = irc_channel_name_gen(irc, name))) { 629 return FALSE; 630 } 631 632 g_free(ic->name); 633 ic->name = full_name; 634 635 return TRUE; 636 } 637 558 638 static gint irc_channel_user_cmp(gconstpointer a_, gconstpointer b_) 559 639 { -
irc_im.c
r531eabd rb1dc403 235 235 } else { 236 236 /* Modules can swallow messages. */ 237 return TRUE;237 goto cleanup; 238 238 } 239 239 } … … 250 250 wrapped = word_wrap(msg, 425); 251 251 irc_send_msg(iu, "PRIVMSG", dst, wrapped, prefix); 252 253 252 g_free(wrapped); 253 254 cleanup: 254 255 g_free(prefix); 255 256 g_free(msg); … … 291 292 292 293 irc_send_msg((irc_user_t *) bu->ui_data, "NOTICE", irc->user->nick, msg->str, NULL); 294 295 g_string_free(msg, TRUE); 293 296 294 297 return TRUE; … … 693 696 static gboolean bee_irc_chat_name_hint(bee_t *bee, struct groupchat *c, const char *name) 694 697 { 695 irc_t *irc = bee->ui_data; 696 irc_channel_t *ic = c->ui_data, *oic; 697 char stripped[MAX_NICK_LENGTH + 1], *full_name; 698 699 if (ic == NULL) { 700 return FALSE; 701 } 702 703 /* Don't rename a channel if the user's in it already. */ 704 if (ic->flags & IRC_CHANNEL_JOINED) { 705 return FALSE; 706 } 707 708 strncpy(stripped, name, MAX_NICK_LENGTH); 709 stripped[MAX_NICK_LENGTH] = '\0'; 710 irc_channel_name_strip(stripped); 711 if (set_getbool(&bee->set, "lcnicks")) { 712 nick_lc(irc, stripped); 713 } 714 715 if (stripped[0] == '\0') { 716 return FALSE; 717 } 718 719 full_name = g_strdup_printf("#%s", stripped); 720 if ((oic = irc_channel_by_name(irc, full_name))) { 721 char *type, *chat_type; 722 723 type = set_getstr(&oic->set, "type"); 724 chat_type = set_getstr(&oic->set, "chat_type"); 725 726 if (type && chat_type && oic->data == FALSE && 727 strcmp(type, "chat") == 0 && 728 strcmp(chat_type, "groupchat") == 0) { 729 /* There's a channel with this name already, but it looks 730 like it's not in use yet. Most likely the IRC client 731 rejoined the channel after a reconnect. Remove it so 732 we can reuse its name. */ 733 irc_channel_free(oic); 734 } else { 735 g_free(full_name); 736 return FALSE; 737 } 738 } 739 740 g_free(ic->name); 741 ic->name = full_name; 742 743 return TRUE; 698 return irc_channel_name_hint(c->ui_data, name); 744 699 } 745 700 -
irc_send.c
r531eabd rb1dc403 55 55 { 56 56 char motd[2048]; 57 s ize_t len;57 ssize_t len; 58 58 int fd; 59 59 -
lib/misc.c
r531eabd rb1dc403 719 719 } 720 720 721 /* Make sure we're still inside the string */722 if (i >= len) {723 return(NULL);724 }725 726 721 /* Copy the found data */ 727 722 return(g_strndup(ret, text + i - ret)); -
lib/oauth.c
r531eabd rb1dc403 98 98 GSList *l, *n; 99 99 100 if ( params == NULL) {100 if (!params) { 101 101 return; 102 102 } … … 104 104 for (l = *params; l; l = n) { 105 105 n = l->next; 106 107 if (strncmp((char *) l->data, key, key_len) == 0 && 108 ((char *) l->data)[key_len] == '=') {109 g_free(l->data);110 *params = g_slist_remove(*params, l->data);106 char *data = l->data; 107 108 if (strncmp(data, key, key_len) == 0 && data[key_len] == '=') { 109 *params = g_slist_remove(*params, data); 110 g_free(data); 111 111 } 112 112 } -
lib/proxy.c
r531eabd rb1dc403 63 63 static int proxy_connect_none(const char *host, unsigned short port_, struct PHB *phb); 64 64 65 static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition cond) 65 static gboolean phb_close(struct PHB *phb) 66 { 67 close(phb->fd); 68 phb->func(phb->data, -1, B_EV_IO_READ); 69 g_free(phb->host); 70 g_free(phb); 71 return FALSE; 72 } 73 74 static gboolean proxy_connected(gpointer data, gint source, b_input_condition cond) 66 75 { 67 76 struct PHB *phb = data; … … 80 89 dup2(new_fd, source); 81 90 closesocket(new_fd); 82 phb->inpa = b_input_add(source, B_EV_IO_WRITE, gaim_io_connected, phb);91 phb->inpa = b_input_add(source, B_EV_IO_WRITE, proxy_connected, phb); 83 92 return FALSE; 84 93 } 85 94 } 86 freeaddrinfo(phb->gai);87 95 closesocket(source); 88 b_event_remove(phb->inpa); 89 phb->inpa = 0; 90 if (phb->proxy_func) { 91 phb->proxy_func(phb->proxy_data, -1, B_EV_IO_READ); 92 } else { 93 phb->func(phb->data, -1, B_EV_IO_READ); 94 g_free(phb); 95 } 96 return FALSE; 97 } 96 source = -1; 97 /* socket is dead, but continue to clean up */ 98 } else { 99 sock_make_blocking(source); 100 } 101 98 102 freeaddrinfo(phb->gai); 99 sock_make_blocking(source);100 103 b_event_remove(phb->inpa); 101 104 phb->inpa = 0; … … 160 163 continue; 161 164 } else { 162 phb->inpa = b_input_add(fd, B_EV_IO_WRITE, gaim_io_connected, phb);165 phb->inpa = b_input_add(fd, B_EV_IO_WRITE, proxy_connected, phb); 163 166 phb->fd = fd; 164 167 … … 206 209 } 207 210 208 close(source); 209 phb->func(phb->data, -1, B_EV_IO_READ); 210 g_free(phb->host); 211 g_free(phb); 212 213 return FALSE; 211 return phb_close(phb); 214 212 } 215 213 … … 226 224 len = sizeof(error); 227 225 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { 228 close(source); 229 phb->func(phb->data, -1, B_EV_IO_READ); 230 g_free(phb->host); 231 g_free(phb); 232 return FALSE; 226 return phb_close(phb); 233 227 } 234 228 sock_make_blocking(source); … … 237 231 phb->host, phb->port); 238 232 if (send(source, cmd, strlen(cmd), 0) < 0) { 239 close(source); 240 phb->func(phb->data, -1, B_EV_IO_READ); 241 g_free(phb->host); 242 g_free(phb); 243 return FALSE; 233 return phb_close(phb); 244 234 } 245 235 … … 252 242 g_free(t2); 253 243 if (send(source, cmd, strlen(cmd), 0) < 0) { 254 close(source); 255 phb->func(phb->data, -1, B_EV_IO_READ); 256 g_free(phb->host); 257 g_free(phb); 258 return FALSE; 244 return phb_close(phb); 259 245 } 260 246 } … … 262 248 g_snprintf(cmd, sizeof(cmd), "\r\n"); 263 249 if (send(source, cmd, strlen(cmd), 0) < 0) { 264 close(source); 265 phb->func(phb->data, -1, B_EV_IO_READ); 266 g_free(phb->host); 267 g_free(phb); 268 return FALSE; 250 return phb_close(phb); 269 251 } 270 252 … … 302 284 } 303 285 304 close(source); 305 phb->func(phb->data, -1, B_EV_IO_READ); 306 g_free(phb->host); 307 g_free(phb); 308 309 return FALSE; 286 return phb_close(phb); 310 287 } 311 288 … … 323 300 len = sizeof(error); 324 301 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { 325 close(source); 326 phb->func(phb->data, -1, B_EV_IO_READ); 327 g_free(phb->host); 328 g_free(phb); 329 return FALSE; 302 return phb_close(phb); 330 303 } 331 304 sock_make_blocking(source); … … 333 306 /* XXX does socks4 not support host name lookups by the proxy? */ 334 307 if (!(hp = gethostbyname(phb->host))) { 335 close(source); 336 phb->func(phb->data, -1, B_EV_IO_READ); 337 g_free(phb->host); 338 g_free(phb); 339 return FALSE; 308 return phb_close(phb); 340 309 } 341 310 … … 350 319 packet[8] = 0; 351 320 if (write(source, packet, 9) != 9) { 352 close(source); 353 phb->func(phb->data, -1, B_EV_IO_READ); 354 g_free(phb->host); 355 g_free(phb); 356 return FALSE; 321 return phb_close(phb); 357 322 } 358 323 … … 383 348 384 349 if (read(source, buf, 10) < 10) { 385 close(source); 386 phb->func(phb->data, -1, B_EV_IO_READ); 387 g_free(phb->host); 388 g_free(phb); 389 return FALSE; 350 return phb_close(phb); 390 351 } 391 352 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { 392 close(source); 393 phb->func(phb->data, -1, B_EV_IO_READ); 394 g_free(phb->host); 395 g_free(phb); 396 return FALSE; 353 return phb_close(phb); 397 354 } 398 355 … … 420 377 421 378 if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { 422 close(source); 423 phb->func(phb->data, -1, B_EV_IO_READ); 424 g_free(phb->host); 425 g_free(phb); 379 phb_close(phb); 426 380 return; 427 381 } … … 438 392 439 393 if (read(source, buf, 2) < 2) { 440 close(source); 441 phb->func(phb->data, -1, B_EV_IO_READ); 442 g_free(phb->host); 443 g_free(phb); 444 return FALSE; 394 return phb_close(phb); 445 395 } 446 396 447 397 if ((buf[0] != 0x01) || (buf[1] != 0x00)) { 448 close(source); 449 phb->func(phb->data, -1, B_EV_IO_READ); 450 g_free(phb->host); 451 g_free(phb); 452 return FALSE; 398 return phb_close(phb); 453 399 } 454 400 … … 466 412 467 413 if (read(source, buf, 2) < 2) { 468 close(source); 469 phb->func(phb->data, -1, B_EV_IO_READ); 470 g_free(phb->host); 471 g_free(phb); 472 return FALSE; 414 return phb_close(phb); 473 415 } 474 416 475 417 if ((buf[0] != 0x05) || (buf[1] == 0xff)) { 476 close(source); 477 phb->func(phb->data, -1, B_EV_IO_READ); 478 g_free(phb->host); 479 g_free(phb); 480 return FALSE; 418 return phb_close(phb); 481 419 } 482 420 … … 489 427 memcpy(buf + 2 + i + 1, proxypass, j); 490 428 if (write(source, buf, 3 + i + j) < 3 + i + j) { 491 close(source); 492 phb->func(phb->data, -1, B_EV_IO_READ); 493 g_free(phb->host); 494 g_free(phb); 495 return FALSE; 429 return phb_close(phb); 496 430 } 497 431 … … 517 451 len = sizeof(error); 518 452 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { 519 close(source); 520 phb->func(phb->data, -1, B_EV_IO_READ); 521 g_free(phb->host); 522 g_free(phb); 523 return FALSE; 453 return phb_close(phb); 524 454 } 525 455 sock_make_blocking(source); … … 539 469 540 470 if (write(source, buf, i) < i) { 541 close(source); 542 phb->func(phb->data, -1, B_EV_IO_READ); 543 g_free(phb->host); 544 g_free(phb); 545 return FALSE; 471 return phb_close(phb); 546 472 } 547 473 -
lib/ssl_gnutls.c
r531eabd rb1dc403 124 124 125 125 if (conn->fd < 0) { 126 g_free(conn->hostname); 126 127 g_free(conn); 127 128 return NULL; … … 314 315 if (source == -1) { 315 316 conn->func(conn->data, 0, NULL, cond); 317 g_free(conn->hostname); 316 318 g_free(conn); 317 319 return FALSE; … … 355 357 conn->func(conn->data, 0, NULL, cond); 356 358 357 gnutls_deinit(conn->session); 358 closesocket(conn->fd); 359 360 g_free(conn); 359 ssl_disconnect(conn); 361 360 } 362 361 } else { … … 364 363 conn->func(conn->data, stver, NULL, cond); 365 364 366 gnutls_deinit(conn->session); 367 closesocket(conn->fd); 368 369 g_free(conn); 365 ssl_disconnect(conn); 370 366 } else { 371 367 /* For now we can't handle non-blocking perfectly everywhere... */ -
nick.c
r531eabd rb1dc403 214 214 } 215 215 216 /* Used for nicks and channel names too! */ 217 void underscore_dedupe(char nick[MAX_NICK_LENGTH + 1]) 218 { 219 if (strlen(nick) < (MAX_NICK_LENGTH - 1)) { 220 nick[strlen(nick) + 1] = 0; 221 nick[strlen(nick)] = '_'; 222 } else { 223 /* We've got no more space for underscores, 224 so truncate it and replace the last three 225 chars with a random "_XX" suffix */ 226 int len = truncate_utf8(nick, MAX_NICK_LENGTH - 3); 227 nick[len] = '_'; 228 g_snprintf(nick + len + 1, 3, "%2x", rand()); 229 } 230 } 231 216 232 void nick_dedupe(bee_user_t *bu, char nick[MAX_NICK_LENGTH + 1]) 217 233 { … … 224 240 while (!nick_ok(irc, nick) || 225 241 ((iu = irc_user_by_name(irc, nick)) && iu->bu != bu)) { 226 if (strlen(nick) < (MAX_NICK_LENGTH - 1)) { 227 nick[strlen(nick) + 1] = 0; 228 nick[strlen(nick)] = '_'; 229 } else { 230 /* We've got no more space for underscores, 231 so truncate it and replace the last three 232 chars with a random "_XX" suffix */ 233 int len = truncate_utf8(nick, MAX_NICK_LENGTH - 3); 234 nick[len] = '_'; 235 g_snprintf(nick + len + 1, 3, "%2x", rand()); 236 } 242 243 underscore_dedupe(nick); 237 244 238 245 if (inf_protection-- == 0) { -
nick.h
r531eabd rb1dc403 28 28 char *nick_get(bee_user_t *bu); 29 29 char *nick_gen(bee_user_t *bu); 30 void underscore_dedupe(char nick[MAX_NICK_LENGTH + 1]); 30 31 void nick_dedupe(bee_user_t * bu, char nick[MAX_NICK_LENGTH + 1]); 31 32 int nick_saved(bee_user_t *bu); -
otr.c
r531eabd rb1dc403 287 287 void otr_irc_free(irc_t *irc) 288 288 { 289 set_t *s; 289 290 otr_t *otr = irc->otr; 290 291 … … 292 293 b_event_remove(otr->timer); 293 294 otrl_userstate_free(otr->us); 295 296 s = set_find(&irc->b->set, "otr_policy"); 297 g_slist_free(s->eval_data); 298 294 299 if (otr->keygen) { 295 300 kill(otr->keygen, SIGTERM); … … 434 439 ic->acc->user, ic->acc->prpl->name, iu->bu->handle, msg, &newmsg, 435 440 &tlvs, NULL, NULL, NULL); 441 442 if (tlvs) { 443 otrl_tlv_free(tlvs); 444 } 436 445 437 446 if (ignore_msg) { … … 472 481 /* libotr wants us to replace our message */ 473 482 /* NB: caller will free old msg */ 474 msg = g_strdup(otrmsg);483 msg = st ? NULL : g_strdup(otrmsg); 475 484 otrl_message_free(otrmsg); 476 485 } … … 1325 1334 1326 1335 log_message(LOGLVL_INFO, "otr: %s", msg); 1336 1337 g_free(msg); 1327 1338 } 1328 1339 … … 2075 2086 } 2076 2087 } 2077 2078 /* vim: set noet ts=4 sw=4: */ -
protocols/bee.h
r531eabd rb1dc403 154 154 G_MODULE_EXPORT void imcb_buddy_times(struct im_connection *ic, const char *handle, time_t login, time_t idle); 155 155 /* Call when a handle says something. 'flags' and 'sent_at may be just 0. */ 156 G_MODULE_EXPORT void imcb_buddy_msg(struct im_connection *ic, const char *handle, c har *msg, guint32 flags,156 G_MODULE_EXPORT void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, guint32 flags, 157 157 time_t sent_at); 158 158 -
protocols/bee_user.c
r531eabd rb1dc403 68 68 } 69 69 70 bee->users = g_slist_remove(bee->users, bu); 71 70 72 g_free(bu->handle); 71 73 g_free(bu->fullname); … … 74 76 g_free(bu->status_msg); 75 77 g_free(bu); 76 77 bee->users = g_slist_remove(bee->users, bu);78 78 79 79 return 1; … … 247 247 } 248 248 249 void imcb_buddy_msg(struct im_connection *ic, const char *handle, c har *msg, uint32_t flags, time_t sent_at)249 void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, uint32_t flags, time_t sent_at) 250 250 { 251 251 bee_t *bee = ic->bee; -
protocols/jabber/Makefile
r531eabd rb1dc403 13 13 14 14 # [SH] Program variables 15 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o s5bytestream.o sasl.o si.o 15 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o s5bytestream.o sasl.o si.o hipchat.o 16 16 17 17 LFLAGS += -r -
protocols/jabber/conference.c
r531eabd rb1dc403 359 359 360 360 if (subject && chat) { 361 s = bud? strchr(bud->ext_jid, '/') : NULL;361 s = (bud && bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL; 362 362 if (s) { 363 363 *s = 0; … … 419 419 } 420 420 if (body && body->text_len > 0) { 421 s = strchr(bud->ext_jid, '/');421 s = (bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL; 422 422 if (s) { 423 423 *s = 0; -
protocols/jabber/iq.c
r531eabd rb1dc403 27 27 static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 28 28 static xt_status jabber_iq_display_vcard(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 29 static int jabber_iq_disco_server(struct im_connection *ic);30 29 31 30 xt_status jabber_pkt_iq(struct xt_node *node, gpointer data) … … 374 373 static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 375 374 { 375 struct jabber_data *jd = ic->proto_data; 376 376 struct xt_node *query, *c; 377 377 int initial = (orig != NULL); … … 388 388 char *name = xt_find_attr(c, "name"); 389 389 char *sub = xt_find_attr(c, "subscription"); 390 char *mention_name = xt_find_attr(c, "mention_name"); 390 391 391 392 if (jid && sub) { … … 396 397 if (name) { 397 398 imcb_rename_buddy(ic, jid, name); 399 } 400 401 /* This could also be used to set the full name as nick for fb/gtalk, 402 * but i'm keeping the old (ugly?) default behavior just to be safe */ 403 if (mention_name && (jd->flags & JFLAG_HIPCHAT)) { 404 imcb_buddy_nick_hint(ic, jid, mention_name); 398 405 } 399 406 } else if (strcmp(sub, "remove") == 0) { … … 855 862 struct xt_node *node, struct xt_node *orig); 856 863 857 staticint jabber_iq_disco_server(struct im_connection *ic)864 int jabber_iq_disco_server(struct im_connection *ic) 858 865 { 859 866 struct xt_node *node, *iq; -
protocols/jabber/jabber.c
r531eabd rb1dc403 61 61 s = set_add(&acc->set, "activity_timeout", "600", set_eval_int, acc); 62 62 63 s = set_add(&acc->set, "oauth", "false", set_eval_oauth, acc);64 65 63 s = set_add(&acc->set, "display_name", NULL, NULL, acc); 66 64 … … 83 81 s = set_add(&acc->set, "server", NULL, set_eval_account, acc); 84 82 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK; 83 84 if (strcmp(acc->prpl->name, "hipchat") == 0) { 85 set_setstr(&acc->set, "server", "chat.hipchat.com"); 86 } else { 87 s = set_add(&acc->set, "oauth", "false", set_eval_oauth, acc); 88 } 85 89 86 90 s = set_add(&acc->set, "ssl", "false", set_eval_bool, acc); … … 121 125 122 126 jd->fd = jd->r_inpa = jd->w_inpa = -1; 127 128 if (strcmp(acc->prpl->name, "hipchat") == 0) { 129 jd->flags |= JFLAG_HIPCHAT; 130 } 123 131 124 132 if (jd->server == NULL) { … … 656 664 { 657 665 struct prpl *ret = g_new0(struct prpl, 1); 666 struct prpl *hipchat = NULL; 658 667 659 668 ret->name = "jabber"; … … 686 695 687 696 register_protocol(ret); 688 } 697 698 /* Another one for hipchat, which has completely different logins */ 699 hipchat = g_memdup(ret, sizeof(struct prpl)); 700 hipchat->name = "hipchat"; 701 register_protocol(hipchat); 702 } -
protocols/jabber/jabber.h
r531eabd rb1dc403 48 48 49 49 JFLAG_GTALK = 0x100000, /* Is Google Talk, as confirmed by iq discovery */ 50 JFLAG_HIPCHAT = 0x200000, /* Is hipchat, because prpl->name says so */ 50 51 51 52 JFLAG_SASL_FB = 0x10000, /* Trying Facebook authentication. */ … … 235 236 #define XMLNS_IBB "http://jabber.org/protocol/ibb" /* XEP-0047 */ 236 237 238 /* Hipchat protocol extensions*/ 239 #define XMLNS_HIPCHAT "http://hipchat.com" 240 #define XMLNS_HIPCHAT_PROFILE "http://hipchat.com/protocol/profile" 241 237 242 /* jabber.c */ 238 243 void jabber_connect(struct im_connection *ic); … … 249 254 xt_status jabber_iq_query_server(struct im_connection *ic, char *jid, char *xmlns); 250 255 void jabber_iq_version_send(struct im_connection *ic, struct jabber_buddy *bud, void *data); 256 int jabber_iq_disco_server(struct im_connection *ic); 251 257 252 258 /* si.c */ … … 341 347 void jabber_chat_invite(struct groupchat *c, char *who, char *message); 342 348 349 /* hipchat.c */ 350 int jabber_get_hipchat_profile(struct im_connection *ic); 351 xt_status jabber_parse_hipchat_profile(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 352 xt_status hipchat_handle_success(struct im_connection *ic, struct xt_node *node); 353 343 354 #endif -
protocols/jabber/jabber_util.c
r531eabd rb1dc403 566 566 567 567 if ((s = strchr(jid, '=')) == NULL) { 568 g_free(jid); 568 569 return NULL; 569 570 } -
protocols/jabber/s5bytestream.c
r531eabd rb1dc403 23 23 24 24 #include "jabber.h" 25 #include "sha1.h"26 25 #include "lib/ftutil.h" 27 26 #include <poll.h> … … 42 41 43 42 /* SHA1( SID + Initiator JID + Target JID) */ 44 char *pseudoad r;43 char *pseudoaddr; 45 44 46 45 gint connect_timeout; … … 130 129 } 131 130 132 g_free(bt->pseudoad r);131 g_free(bt->pseudoaddr); 133 132 134 133 while (bt->streamhosts) { … … 254 253 } 255 254 255 void jabber_bs_remove_events(struct bs_transfer *bt) 256 { 257 struct jabber_transfer *tf = bt->tf; 258 259 if (tf->watch_out) { 260 b_event_remove(tf->watch_out); 261 tf->watch_out = 0; 262 } 263 264 if (tf->watch_in) { 265 b_event_remove(tf->watch_in); 266 tf->watch_in = 0; 267 } 268 269 if (tf->fd != -1) { 270 closesocket(tf->fd); 271 tf->fd = -1; 272 } 273 274 if (bt->connect_timeout) { 275 b_event_remove(bt->connect_timeout); 276 bt->connect_timeout = 0; 277 } 278 } 279 256 280 /* Bad luck */ 257 281 void jabber_bs_canceled(file_transfer_t *ft, char *reason) … … 260 284 261 285 imcb_log(tf->ic, "File transfer aborted: %s", reason); 286 } 287 288 static struct jabber_transfer *get_ft_by_sid(GSList *tflist, char *sid) { 289 GSList *l; 290 for (l = tflist; l; l = g_slist_next(l)) { 291 struct jabber_transfer *tft = l->data; 292 if ((strcmp(tft->sid, sid) == 0)) { 293 return tft; 294 } 295 } 296 return NULL; 297 } 298 299 /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value 300 * Returns a newly allocated string */ 301 static char *generate_pseudoaddr(char *sid, char *ini_jid, char *tgt_jid) { 302 char *contents = g_strconcat(sid, ini_jid, tgt_jid, NULL); 303 char *hash_hex = g_compute_checksum_for_string(G_CHECKSUM_SHA1, contents, -1); 304 g_free(contents); 305 return hash_hex; 306 } 307 308 static jabber_streamhost_t *jabber_streamhost_new(char *jid, char *host, int port) 309 { 310 jabber_streamhost_t *sh = g_new0(jabber_streamhost_t, 1); 311 sh->jid = g_strdup(jid); 312 sh->host = g_strdup(host); 313 if (port) { 314 g_snprintf(sh->port, sizeof(sh->port), "%u", port); 315 } 316 return sh; 262 317 } 263 318 … … 270 325 struct jabber_data *jd = ic->proto_data; 271 326 struct jabber_transfer *tf = NULL; 272 GSList *tflist;273 327 struct bs_transfer *bt; 274 328 GSList *shlist = NULL; 275 329 struct xt_node *shnode; 276 277 sha1_state_t sha;278 char hash_hex[41];279 unsigned char hash[20];280 int i;281 330 282 331 if (!(iq_id = xt_find_attr(node, "id")) || … … 303 352 (port_s = xt_find_attr(shnode, "port")) && 304 353 (sscanf(port_s, "%d", &port) == 1)) { 305 jabber_streamhost_t *sh = g_new0(jabber_streamhost_t, 1); 306 sh->jid = g_strdup(jid); 307 sh->host = g_strdup(host); 308 sprintf(sh->port, "%u", port); 309 shlist = g_slist_append(shlist, sh); 354 shlist = g_slist_append(shlist, jabber_streamhost_new(jid, host, port)); 310 355 } 311 356 shnode = shnode->next; … … 317 362 } 318 363 319 /* Let's see if we can find out what this bytestream should be for... */ 320 321 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) { 322 struct jabber_transfer *tft = tflist->data; 323 if ((strcmp(tft->sid, sid) == 0) && 324 (strcmp(tft->ini_jid, ini_jid) == 0) && 325 (strcmp(tft->tgt_jid, tgt_jid) == 0)) { 326 tf = tft; 327 break; 328 } 329 } 330 331 if (!tf) { 364 if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) { 332 365 imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid); 333 366 return XT_HANDLED; … … 339 372 340 373 tf->ft->canceled = jabber_bs_canceled; 341 342 /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */343 sha1_init(&sha);344 sha1_append(&sha, (unsigned char *) sid, strlen(sid));345 sha1_append(&sha, (unsigned char *) ini_jid, strlen(ini_jid));346 sha1_append(&sha, (unsigned char *) tgt_jid, strlen(tgt_jid));347 sha1_finish(&sha, hash);348 349 for (i = 0; i < 20; i++) {350 sprintf(hash_hex + i * 2, "%02x", hash[i]);351 }352 374 353 375 bt = g_new0(struct bs_transfer, 1); … … 356 378 bt->sh = shlist->data; 357 379 bt->phase = BS_PHASE_CONNECT; 358 bt->pseudoad r = g_strdup(hash_hex);380 bt->pseudoaddr = generate_pseudoaddr(sid, ini_jid, tgt_jid); 359 381 tf->streamhandle = bt; 360 382 tf->ft->free = jabber_bs_free_transfer; … … 451 473 .rsv = 0, 452 474 .atyp = 0x03, 453 .addrlen = strlen(bt->pseudoad r),475 .addrlen = strlen(bt->pseudoaddr), 454 476 .port = 0 455 477 }; … … 468 490 469 491 /* copy hash into connect message */ 470 memcpy(socks5_connect.address, bt->pseudoad r, socks5_connect.addrlen);492 memcpy(socks5_connect.address, bt->pseudoaddr, socks5_connect.addrlen); 471 493 472 494 ASSERTSOCKOP(send(fd, &socks5_connect, sizeof(struct socks5_message), 0), "Sending SOCKS5 Connect"); … … 558 580 if (shlist && shlist->next) { 559 581 bt->sh = shlist->next->data; 582 jabber_bs_remove_events(bt); 560 583 return jabber_bs_recv_handshake(bt, -1, 0); 561 584 } … … 731 754 struct jabber_data *jd = ic->proto_data; 732 755 struct bs_transfer *bt; 733 GSList *tflist;734 756 struct xt_node *c; 735 757 char *sid, *jid; … … 750 772 /* Let's see if we can find out what this bytestream should be for... */ 751 773 752 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) { 753 struct jabber_transfer *tft = tflist->data; 754 if ((strcmp(tft->sid, sid) == 0)) { 755 tf = tft; 756 break; 757 } 758 } 759 760 if (!tf) { 774 if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) { 761 775 imcb_log(ic, "WARNING: Received SOCKS5 bytestream reply to unknown request"); 762 776 return XT_HANDLED; … … 776 790 /* using a proxy, abort listen */ 777 791 778 if (tf->watch_in) { 779 b_event_remove(tf->watch_in); 780 tf->watch_in = 0; 781 } 782 783 if (tf->fd != -1) { 784 closesocket(tf->fd); 785 tf->fd = -1; 786 } 787 788 if (bt->connect_timeout) { 789 b_event_remove(bt->connect_timeout); 790 bt->connect_timeout = 0; 791 } 792 jabber_bs_remove_events(bt); 792 793 793 794 GSList *shlist; … … 838 839 { 839 840 char *sid; 840 GSList *tflist;841 841 struct jabber_transfer *tf = NULL; 842 842 struct xt_node *query; … … 846 846 sid = xt_find_attr(query, "sid"); 847 847 848 for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) { 849 struct jabber_transfer *tft = tflist->data; 850 if ((strcmp(tft->sid, sid) == 0)) { 851 tf = tft; 852 break; 853 } 854 } 855 856 if (!tf) { 848 if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) { 857 849 imcb_log(ic, "WARNING: Received SOCKS5 bytestream activation for unknown stream"); 858 850 return XT_HANDLED; … … 883 875 *port++ = '\0'; 884 876 885 sh = g_new0(jabber_streamhost_t, 1); 886 sh->jid = g_strdup(jid); 887 sh->host = g_strdup(host); 888 g_snprintf(sh->port, sizeof(sh->port), "%s", port); 877 sh = jabber_streamhost_new(jid, host, 0); 878 strncpy(sh->port, port, sizeof(sh->port)); 889 879 890 880 return sh; … … 910 900 if (strcmp(proxy, "<local>") == 0) { 911 901 if ((tf->fd = ft_listen(&tf->saddr, host, port, jd->fd, FALSE, &errmsg)) != -1) { 912 sh = g_new0(jabber_streamhost_t, 1); 913 sh->jid = g_strdup(tf->ini_jid); 914 sh->host = g_strdup(host); 915 g_snprintf(sh->port, sizeof(sh->port), "%s", port); 902 sh = jabber_streamhost_new(tf->ini_jid, host, 0); 903 strncpy(sh->port, port, sizeof(sh->port)); 916 904 bt->streamhosts = g_slist_append(bt->streamhosts, sh); 917 905 … … 948 936 { 949 937 struct bs_transfer *bt; 950 sha1_state_t sha;951 char hash_hex[41];952 unsigned char hash[20];953 int i, ret;954 955 /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */956 sha1_init(&sha);957 sha1_append(&sha, (unsigned char *) tf->sid, strlen(tf->sid));958 sha1_append(&sha, (unsigned char *) tf->ini_jid, strlen(tf->ini_jid));959 sha1_append(&sha, (unsigned char *) tf->tgt_jid, strlen(tf->tgt_jid));960 sha1_finish(&sha, hash);961 962 for (i = 0; i < 20; i++) {963 sprintf(hash_hex + i * 2, "%02x", hash[i]);964 }965 938 966 939 bt = g_new0(struct bs_transfer, 1); 967 940 bt->tf = tf; 968 941 bt->phase = BS_PHASE_CONNECT; 969 bt->pseudoad r = g_strdup(hash_hex);942 bt->pseudoaddr = generate_pseudoaddr(tf->sid, tf->ini_jid, tf->tgt_jid); 970 943 tf->streamhandle = bt; 971 944 tf->ft->free = jabber_bs_free_transfer; … … 974 947 jabber_si_set_proxies(bt); 975 948 976 ret = jabber_bs_send_request(tf, bt->streamhosts); 977 978 return ret; 949 return jabber_bs_send_request(tf, bt->streamhosts); 979 950 } 980 951 … … 1139 1110 socks5_connect.atyp); 1140 1111 } 1141 if (!(memcmp(socks5_connect.address, bt->pseudoad r, 40) == 0)) {1112 if (!(memcmp(socks5_connect.address, bt->pseudoaddr, 40) == 0)) { 1142 1113 return jabber_bs_abort(bt, "SOCKS5 Connect message contained wrong digest"); 1143 1114 } -
protocols/jabber/sasl.c
r531eabd rb1dc403 42 42 "https://www.facebook.com/dialog/oauth", 43 43 "https://graph.facebook.com/oauth/access_token", 44 "http ://www.bitlbee.org/main.php/Facebook/oauth2.html",44 "https://www.bitlbee.org/main.php/Facebook/oauth2.html", 45 45 "offline_access,xmpp_login", 46 46 "126828914005625", … … 55 55 char *s; 56 56 int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_fb = 0; 57 int want_oauth = FALSE ;57 int want_oauth = FALSE, want_hipchat = FALSE; 58 58 GString *mechs; 59 59 … … 75 75 76 76 want_oauth = set_getbool(&ic->acc->set, "oauth"); 77 want_hipchat = (jd->flags & JFLAG_HIPCHAT); 77 78 78 79 mechs = g_string_new(""); … … 111 112 112 113 reply = xt_new_node("auth", NULL, NULL); 113 xt_add_attr(reply, "xmlns", XMLNS_SASL); 114 if (!want_hipchat) { 115 xt_add_attr(reply, "xmlns", XMLNS_SASL); 116 } else { 117 xt_add_attr(reply, "xmlns", XMLNS_HIPCHAT); 118 } 114 119 115 120 if (sup_gtalk && want_oauth) { … … 143 148 } else if (sup_plain) { 144 149 int len; 145 146 xt_add_attr(reply, "mechanism", "PLAIN"); 150 GString *gs; 151 char *username; 152 153 if (!want_hipchat) { 154 xt_add_attr(reply, "mechanism", "PLAIN"); 155 username = jd->username; 156 } else { 157 username = jd->me; 158 } 159 160 /* set an arbitrary initial size to avoid reallocations */ 161 gs = g_string_sized_new(128); 147 162 148 163 /* With SASL PLAIN in XMPP, the text should be b64(\0user\0pass) */ 149 len = strlen(jd->username) + strlen(ic->acc->pass) + 2; 150 s = g_malloc(len + 1); 151 s[0] = 0; 152 strcpy(s + 1, jd->username); 153 strcpy(s + 2 + strlen(jd->username), ic->acc->pass); 164 g_string_append_c(gs, '\0'); 165 g_string_append(gs, username); 166 g_string_append_c(gs, '\0'); 167 g_string_append(gs, ic->acc->pass); 168 if (want_hipchat) { 169 /* Hipchat's variation adds \0resource at the end */ 170 g_string_append_c(gs, '\0'); 171 g_string_append(gs, set_getstr(&ic->acc->set, "resource")); 172 } 173 174 len = gs->len; 175 s = g_string_free(gs, FALSE); 176 154 177 reply->text = base64_encode((unsigned char *) s, len); 155 178 reply->text_len = strlen(reply->text); … … 397 420 imcb_log(ic, "Authentication finished"); 398 421 jd->flags |= JFLAG_AUTHENTICATED | JFLAG_STREAM_RESTART; 422 423 if (jd->flags & JFLAG_HIPCHAT) { 424 return hipchat_handle_success(ic, node); 425 } 399 426 } else if (strcmp(node->name, "failure") == 0) { 400 427 imcb_error(ic, "Authentication failure"); -
protocols/msn/Makefile
r531eabd rb1dc403 13 13 14 14 # [SH] Program variables 15 objects = msn.o msn_util.o ns.o s b.o soap.o tables.o15 objects = msn.o msn_util.o ns.o soap.o tables.o gw.o 16 16 17 17 LFLAGS += -r -
protocols/msn/msn.c
r531eabd rb1dc403 30 30 int msn_chat_id; 31 31 GSList *msn_connections; 32 GSList *msn_switchboards;33 32 34 33 static char *set_eval_display_name(set_t *set, char *value); … … 41 40 s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY; 42 41 43 s = set_add(&acc->set, "server", MSN_NS_HOST, set_eval_account, acc);42 s = set_add(&acc->set, "server", NULL, set_eval_account, acc); 44 43 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY; 45 44 … … 48 47 49 48 set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc); 50 set_add(&acc->set, "switchboard_keepalives", "false", set_eval_bool, acc);51 49 52 50 acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE | … … 58 56 struct im_connection *ic = imcb_new(acc); 59 57 struct msn_data *md = g_new0(struct msn_data, 1); 58 char *server = set_getstr(&ic->acc->set, "server"); 60 59 61 60 ic->proto_data = md; 62 61 ic->flags |= OPT_PONGS | OPT_PONGED; 62 63 if (!server) { 64 server = "geo.gateway.messenger.live.com"; 65 } 63 66 64 67 if (strchr(acc->user, '@') == NULL) { … … 71 74 md->away_state = msn_away_state_list; 72 75 md->domaintree = g_tree_new(msn_domaintree_cmp); 73 md->ns->fd = -1; 76 md->fd = -1; 77 md->is_http = TRUE; 74 78 75 79 msn_connections = g_slist_prepend(msn_connections, ic); 76 80 77 81 imcb_log(ic, "Connecting"); 78 msn_ns_connect(ic, md->ns, 79 set_getstr(&ic->acc->set, "server"), 82 msn_ns_connect(ic, server, 80 83 set_getint(&ic->acc->set, "port")); 81 84 } … … 88 91 89 92 if (md) { 90 /** Disabling MSN ft support for now. 91 while( md->filetransfers ) { 92 imcb_file_canceled( md->filetransfers->data, "Closing connection" ); 93 } 94 */ 95 96 msn_ns_close(md->ns); 97 98 while (md->switchboards) { 99 msn_sb_destroy(md->switchboards->data); 100 } 101 102 msn_msgq_purge(ic, &md->msgq); 93 msn_ns_close(md); 94 103 95 msn_soapq_flush(ic, FALSE); 104 96 … … 112 104 while (md->groups) { 113 105 struct msn_group *mg = md->groups->data; 106 md->groups = g_slist_remove(md->groups, mg); 114 107 g_free(mg->id); 115 108 g_free(mg->name); 116 109 g_free(mg); 117 md->groups = g_slist_remove(md->groups, mg);118 110 } 119 111 … … 127 119 while (md->grpq) { 128 120 struct msn_groupadd *ga = md->grpq->data; 121 md->grpq = g_slist_remove(md->grpq, ga); 129 122 g_free(ga->group); 130 123 g_free(ga->who); 131 124 g_free(ga); 132 md->grpq = g_slist_remove(md->grpq, ga);133 125 } 134 126 … … 152 144 { 153 145 struct bee_user *bu = bee_user_by_handle(ic->bee, ic, who); 154 struct msn_buddy_data *bd = bu ? bu->data : NULL;155 struct msn_switchboard *sb;156 146 157 147 #ifdef DEBUG 158 148 if (strcmp(who, "raw") == 0) { 159 149 msn_ns_write(ic, -1, "%s\r\n", message); 160 } else 150 return 0; 151 } 161 152 #endif 162 if (bd && bd->flags & MSN_BUDDY_FED) { 163 msn_ns_sendmessage(ic, bu, message); 164 } else if ((sb = msn_sb_by_handle(ic, who))) { 165 return(msn_sb_sendmessage(sb, message)); 166 } else { 167 struct msn_message *m; 168 169 /* Create a message. We have to arrange a usable switchboard, and send the message later. */ 170 m = g_new0(struct msn_message, 1); 171 m->who = g_strdup(who); 172 m->text = g_strdup(message); 173 174 return msn_sb_write_msg(ic, m); 175 } 176 153 154 msn_ns_sendmessage(ic, bu, message); 177 155 return(0); 178 156 } … … 196 174 static void msn_set_away(struct im_connection *ic, char *state, char *message) 197 175 { 198 char *uux;199 176 struct msn_data *md = ic->proto_data; 177 char *nick, *psm, *idle, *statecode, *body, *buf; 200 178 201 179 if (state == NULL) { … … 205 183 } 206 184 207 if (!msn_ns_write(ic, -1, "CHG %d %s %d:%02d\r\n", ++md->trId, md->away_state->code, MSN_CAP1, MSN_CAP2)) { 208 return; 209 } 210 211 uux = g_markup_printf_escaped("<EndpointData><Capabilities>%d:%02d" 212 "</Capabilities></EndpointData>", 213 MSN_CAP1, MSN_CAP2); 214 msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux); 215 g_free(uux); 216 217 uux = g_markup_printf_escaped("<PrivateEndpointData><EpName>%s</EpName>" 218 "<Idle>%s</Idle><ClientType>%d</ClientType>" 219 "<State>%s</State></PrivateEndpointData>", 220 md->uuid, 221 strcmp(md->away_state->code, "IDL") ? "false" : "true", 222 1, /* ? */ 223 md->away_state->code); 224 msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux); 225 g_free(uux); 226 227 uux = g_markup_printf_escaped("<Data><DDP></DDP><PSM>%s</PSM>" 228 "<CurrentMedia></CurrentMedia>" 229 "<MachineGuid>%s</MachineGuid></Data>", 230 message ? message : "", md->uuid); 231 msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux); 232 g_free(uux); 185 statecode = (char *) md->away_state->code; 186 nick = set_getstr(&ic->acc->set, "display_name"); 187 psm = message ? message : ""; 188 idle = (strcmp(statecode, "IDL") == 0) ? "false" : "true"; 189 190 body = g_markup_printf_escaped(MSN_PUT_USER_BODY, 191 nick, psm, psm, md->uuid, statecode, md->uuid, idle, statecode, 192 MSN_CAP1, MSN_CAP2, MSN_CAP1, MSN_CAP2 193 ); 194 195 buf = g_strdup_printf(MSN_PUT_HEADERS, ic->acc->user, ic->acc->user, md->uuid, 196 "/user", "application/user+xml", 197 strlen(body), body); 198 msn_ns_write(ic, -1, "PUT %d %zd\r\n%s", ++md->trId, strlen(buf), buf); 199 200 g_free(buf); 201 g_free(body); 233 202 } 234 203 … … 256 225 static void msn_chat_msg(struct groupchat *c, char *message, int flags) 257 226 { 258 struct msn_switchboard *sb = msn_sb_by_chat(c); 259 260 if (sb) { 261 msn_sb_sendmessage(sb, message); 262 } 263 /* FIXME: Error handling (although this can't happen unless something's 264 already severely broken) disappeared here! */ 227 /* TODO: groupchats*/ 265 228 } 266 229 267 230 static void msn_chat_invite(struct groupchat *c, char *who, char *message) 268 231 { 269 struct msn_switchboard *sb = msn_sb_by_chat(c); 270 271 if (sb) { 272 msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, who); 273 } 232 /* TODO: groupchats*/ 274 233 } 275 234 276 235 static void msn_chat_leave(struct groupchat *c) 277 236 { 278 struct msn_switchboard *sb = msn_sb_by_chat(c); 279 280 if (sb) { 281 msn_sb_write(sb, "OUT\r\n"); 282 } 237 /* TODO: groupchats*/ 283 238 } 284 239 285 240 static struct groupchat *msn_chat_with(struct im_connection *ic, char *who) 286 241 { 287 struct msn_switchboard *sb;242 /* TODO: groupchats*/ 288 243 struct groupchat *c = imcb_chat_new(ic, who); 289 290 if ((sb = msn_sb_by_handle(ic, who))) { 291 debug("Converting existing switchboard to %s to a groupchat", who); 292 return msn_sb_to_chat(sb); 293 } else { 294 struct msn_message *m; 295 296 /* Create a magic message. This is quite hackish, but who cares? :-P */ 297 m = g_new0(struct msn_message, 1); 298 m->who = g_strdup(who); 299 m->text = g_strdup(GROUPCHAT_SWITCHBOARD_MESSAGE); 300 301 msn_sb_write_msg(ic, m); 302 303 return c; 304 } 244 return c; 305 245 } 306 246 … … 322 262 static void msn_add_deny(struct im_connection *ic, char *who) 323 263 { 324 struct msn_switchboard *sb;325 326 264 msn_buddy_list_add(ic, MSN_BUDDY_BL, who, who, NULL); 327 328 /* If there's still a conversation with this person, close it. */329 if ((sb = msn_sb_by_handle(ic, who))) {330 msn_sb_destroy(sb);331 }332 265 } 333 266 … … 462 395 ret->buddy_action = msn_buddy_action; 463 396 464 //ret->transfer_request = msn_ftp_transfer_request;465 466 397 register_protocol(ret); 467 398 } -
protocols/msn/msn.h
r531eabd rb1dc403 32 32 #define NUDGE_MESSAGE "\r\r\rSHAKE THAT THING\r\r\r" 33 33 #define GROUPCHAT_SWITCHBOARD_MESSAGE "\r\r\rME WANT TALK TO MANY PEOPLE\r\r\r" 34 #define SB_KEEPALIVE_MESSAGE "\r\r\rDONT HANG UP ON ME!\r\r\r"35 34 36 35 #ifdef DEBUG_MSN … … 60 59 #define MSNP11_PROD_KEY "C1BX{V4W}Q3*10SM" 61 60 #define MSNP11_PROD_ID "PROD0120PW!CCV9@" 62 #define MSNP_VER "MSNP 18"61 #define MSNP_VER "MSNP21" 63 62 #define MSNP_BUILD "14.0.8117.416" 64 63 … … 68 67 #define MSN_CAP2 0x0000 69 68 70 #define MSN_MESSAGE_HEADERS "MIME-Version: 1.0\r\n" \ 69 #define MSN_BASE_HEADERS \ 70 "Routing: 1.0\r\n" \ 71 "To: 1:%s\r\n" \ 72 "From: 1:%s;epid={%s}\r\n" \ 73 "\r\n" \ 74 "Reliability: 1.0\r\n" \ 75 "\r\n" 76 77 #define MSN_MESSAGE_HEADERS MSN_BASE_HEADERS \ 78 "Messaging: 2.0\r\n" \ 79 "Message-Type: Text\r\n" \ 80 "Content-Length: %zd\r\n" \ 71 81 "Content-Type: text/plain; charset=UTF-8\r\n" \ 72 "User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ 73 "X-MMS-IM-Format: FN=MS%20Shell%20Dlg; EF=; CO=0; CS=0; PF=0\r\n" \ 74 "\r\n" 82 "X-MMS-IM-Format: FN=Segoe%%20UI; EF=; CO=0; CS=0; PF=0\r\n" \ 83 "\r\n" \ 84 "%s" 85 86 #define MSN_PUT_HEADERS MSN_BASE_HEADERS \ 87 "Publication: 1.0\r\n" \ 88 "Uri: %s\r\n" \ 89 "Content-Type: %s\r\n" \ 90 "Content-Length: %zd\r\n" \ 91 "\r\n" \ 92 "%s" 93 94 #define MSN_PUT_USER_BODY \ 95 "<user>" \ 96 "<s n=\"PE\"><UserTileLocation></UserTileLocation><FriendlyName>%s</FriendlyName><PSM>%s</PSM><DDP></DDP>" \ 97 "<Scene></Scene><ASN></ASN><ColorScheme>-3</ColorScheme><BDG></BDG><RUM>%s</RUM><RUL></RUL><RLT>0</RLT>" \ 98 "<RID></RID><SUL></SUL><MachineGuid>%s</MachineGuid></s>" \ 99 "<s n=\"IM\"><Status>%s</Status><CurrentMedia></CurrentMedia></s>" \ 100 "<sep n=\"PD\"><ClientType>1</ClientType><EpName>%s</EpName><Idle>%s</Idle><State>%s</State></sep>" \ 101 "<sep n=\"PE\"><VER>BitlBee:" BITLBEE_VERSION "</VER><TYP>1</TYP><Capabilities>%d:%d</Capabilities></sep>" \ 102 "<sep n=\"IM\"><Capabilities>%d:%d</Capabilities></sep>" \ 103 "</user>" 75 104 76 105 #define MSN_TYPING_HEADERS "MIME-Version: 1.0\r\n" \ … … 84 113 "ID: 1\r\n" \ 85 114 "\r\n" 86 87 #define MSN_SB_KEEPALIVE_HEADERS "MIME-Version: 1.0\r\n" \88 "Content-Type: text/x-ping\r\n" \89 "\r\n\r\n"90 115 91 116 #define PROFILE_URL "http://members.msn.com/" … … 99 124 } msn_flags_t; 100 125 101 struct msn_handler_data { 126 struct msn_gw { 127 char *last_host; 128 int port; 129 gboolean ssl; 130 131 char *session_id; 132 133 GByteArray *in; 134 GByteArray *out; 135 136 int poll_timeout; 137 138 b_event_handler callback; 139 140 struct im_connection *ic; 141 struct msn_data *md; 142 143 gboolean open; 144 gboolean waiting; 145 gboolean polling; 146 }; 147 148 struct msn_data { 102 149 int fd, inpa; 103 150 int rxlen; … … 107 154 char *cmd_text; 108 155 109 /* Either ic or sb */110 gpointer data;111 112 int (*exec_command) (struct msn_handler_data *handler, char **cmd, int count);113 int (*exec_message) (struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int count);114 };115 116 struct msn_data {117 156 struct im_connection *ic; 118 157 119 struct msn_handler_data ns[1];120 158 msn_flags_t flags; 121 159 … … 126 164 127 165 GSList *msgq, *grpq, *soapq; 128 GSList *switchboards;129 int sb_failures;130 time_t first_sb_failure;131 166 132 167 const struct msn_away_state *away_state; … … 139 174 GTree *domaintree; 140 175 int adl_todo; 141 }; 142 143 struct msn_switchboard { 144 struct im_connection *ic; 145 146 /* The following two are also in the handler. TODO: Clean up. */ 147 int fd; 148 gint inp; 149 struct msn_handler_data *handler; 150 gint keepalive; 151 152 int trId; 153 int ready; 154 155 int session; 156 char *key; 157 158 GSList *msgq; 159 char *who; 160 struct groupchat *chat; 176 177 gboolean is_http; 178 struct msn_gw *gw; 161 179 }; 162 180 … … 205 223 #define STATUS_FATAL 1 206 224 #define STATUS_SB_FATAL 2 207 #define STATUS_SB_IM_SPARE 4 /* Make one-to-one conversation switchboard available again, invite failed. */208 #define STATUS_SB_CHAT_SPARE 8 /* Same, but also for groupchats (not used yet). */209 225 210 226 extern int msn_chat_id; … … 218 234 before doing *anything* else. */ 219 235 extern GSList *msn_connections; 220 extern GSList *msn_switchboards;221 236 222 237 /* ns.c */ 223 238 int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) G_GNUC_PRINTF(3, 4); 224 gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler,const char *host, int port);225 void msn_ns_close(struct msn_ handler_data *handler);239 gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port); 240 void msn_ns_close(struct msn_data *handler); 226 241 void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error); 227 242 void msn_auth_got_contact_list(struct im_connection *ic); 228 243 int msn_ns_finish_login(struct im_connection *ic); 229 244 int msn_ns_sendmessage(struct im_connection *ic, struct bee_user *bu, const char *text); 230 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq); 245 int msn_ns_command(struct msn_data *md, char **cmd, int num_parts); 246 int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts); 231 247 232 248 /* msn_util.c */ … … 235 251 int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group); 236 252 void msn_buddy_ask(bee_user_t *bu); 237 char **msn_linesplit(char *line); 238 int msn_handler(struct msn_handler_data *h); 239 void msn_msgq_purge(struct im_connection *ic, GSList **list); 253 void msn_queue_feed(struct msn_data *h, char *bytes, int st); 254 int msn_handler(struct msn_data *h); 240 255 char *msn_p11_challenge(char *challenge); 241 256 gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_); … … 251 266 const struct msn_status_code *msn_status_by_number(int number); 252 267 253 /* sb.c */ 254 int msn_sb_write(struct msn_switchboard *sb, const char *fmt, ...) G_GNUC_PRINTF(2, 3);; 255 struct msn_switchboard *msn_sb_create(struct im_connection *ic, char *host, int port, char *key, int session); 256 struct msn_switchboard *msn_sb_by_handle(struct im_connection *ic, const char *handle); 257 struct msn_switchboard *msn_sb_by_chat(struct groupchat *c); 258 struct msn_switchboard *msn_sb_spare(struct im_connection *ic); 259 int msn_sb_sendmessage(struct msn_switchboard *sb, char *text); 260 struct groupchat *msn_sb_to_chat(struct msn_switchboard *sb); 261 void msn_sb_destroy(struct msn_switchboard *sb); 262 gboolean msn_sb_connected(gpointer data, gint source, b_input_condition cond); 263 int msn_sb_write_msg(struct im_connection *ic, struct msn_message *m); 264 void msn_sb_start_keepalives(struct msn_switchboard *sb, gboolean initial); 265 void msn_sb_stop_keepalives(struct msn_switchboard *sb); 268 /* gw.c */ 269 struct msn_gw *msn_gw_new(struct im_connection *ic); 270 void msn_gw_free(struct msn_gw *gw); 271 void msn_gw_open(struct msn_gw *gw); 272 ssize_t msn_gw_read(struct msn_gw *gw, char **buf); 273 void msn_gw_write(struct msn_gw *gw, char *buf, size_t len); 266 274 267 275 #endif //_MSN_H -
protocols/msn/msn_util.c
r531eabd rb1dc403 55 55 56 56 *groupid = '\0'; 57 #if 058 if (group) {59 int i;60 for (i = 0; i < md->groupcount; i++) {61 if (g_strcasecmp(md->grouplist[i], group) == 0) {62 g_snprintf(groupid, sizeof(groupid), " %d", i);63 break;64 }65 }66 67 if (*groupid == '\0') {68 /* Have to create this group, it doesn't exist yet. */69 struct msn_groupadd *ga;70 GSList *l;71 72 for (l = md->grpq; l; l = l->next) {73 ga = l->data;74 if (g_strcasecmp(ga->group, group) == 0) {75 break;76 }77 }78 79 ga = g_new0(struct msn_groupadd, 1);80 ga->who = g_strdup(who);81 ga->group = g_strdup(group);82 md->grpq = g_slist_prepend(md->grpq, ga);83 84 if (l == NULL) {85 char groupname[strlen(group) + 1];86 strcpy(groupname, group);87 http_encode(groupname);88 g_snprintf(buf, sizeof(buf), "ADG %d %s %d\r\n", ++md->trId, groupname, 0);89 return msn_write(ic, buf, strlen(buf));90 } else {91 /* This can happen if the user's doing lots of adds to a92 new group at once; we're still waiting for the server93 to confirm group creation. */94 return 1;95 }96 }97 }98 #endif99 57 100 58 if (!((bu = bee_user_by_handle(ic->bee, ic, who)) || … … 132 90 133 91 *groupid = '\0'; 134 #if 0135 if (group) {136 int i;137 for (i = 0; i < md->groupcount; i++) {138 if (g_strcasecmp(md->grouplist[i], group) == 0) {139 g_snprintf(groupid, sizeof(groupid), " %d", i);140 break;141 }142 }143 }144 #endif145 92 146 93 if (!(bu = bee_user_by_handle(ic->bee, ic, who)) || … … 174 121 }; 175 122 176 static void msn_buddy_ask_ yes(void *data)123 static void msn_buddy_ask_free(void *data) 177 124 { 178 125 struct msn_buddy_ask_data *bla = data; 179 180 msn_buddy_list_add(bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL);181 182 imcb_ask_add(bla->ic, bla->handle, NULL);183 126 184 127 g_free(bla->handle); … … 187 130 } 188 131 132 static void msn_buddy_ask_yes(void *data) 133 { 134 struct msn_buddy_ask_data *bla = data; 135 136 msn_buddy_list_add(bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL); 137 138 imcb_ask_add(bla->ic, bla->handle, NULL); 139 140 msn_buddy_ask_free(bla); 141 } 142 189 143 static void msn_buddy_ask_no(void *data) 190 144 { … … 193 147 msn_buddy_list_add(bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL); 194 148 195 g_free(bla->handle); 196 g_free(bla->realname); 197 g_free(bla); 149 msn_buddy_ask_free(bla); 198 150 } 199 151 … … 216 168 "The user %s (%s) wants to add you to his/her buddy list.", 217 169 bu->handle, bu->fullname); 218 imcb_ask(bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no); 219 } 220 221 /* *NOT* thread-safe, but that's not a problem for now... */ 222 char **msn_linesplit(char *line) 223 { 224 static char **ret = NULL; 225 static int size = 3; 226 int i, n = 0; 227 228 if (ret == NULL) { 229 ret = g_new0(char*, size); 230 } 231 232 for (i = 0; line[i] && line[i] == ' '; i++) { 233 ; 234 } 235 if (line[i]) { 236 ret[n++] = line + i; 237 for (i++; line[i]; i++) { 238 if (line[i] == ' ') { 239 line[i] = 0; 240 } else if (line[i] != ' ' && !line[i - 1]) { 241 ret[n++] = line + i; 242 } 243 244 if (n >= size) { 245 ret = g_renew(char*, ret, size += 2); 246 } 247 } 248 } 249 ret[n] = NULL; 250 251 return(ret); 170 171 imcb_ask_with_free(bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no, msn_buddy_ask_free); 172 } 173 174 void msn_queue_feed(struct msn_data *h, char *bytes, int st) 175 { 176 h->rxq = g_renew(char, h->rxq, h->rxlen + st); 177 memcpy(h->rxq + h->rxlen, bytes, st); 178 h->rxlen += st; 179 180 if (getenv("BITLBEE_DEBUG")) { 181 fprintf(stderr, "\n\x1b[92m<<< "); 182 write(2, bytes , st); 183 fprintf(stderr, "\x1b[97m"); 184 } 252 185 } 253 186 … … 260 193 1: OK */ 261 194 262 int msn_handler(struct msn_handler_data *h) 263 { 264 int st; 265 266 h->rxq = g_renew(char, h->rxq, h->rxlen + 1024); 267 st = read(h->fd, h->rxq + h->rxlen, 1024); 268 h->rxlen += st; 269 270 if (st <= 0) { 271 return(-1); 272 } 273 274 if (getenv("BITLBEE_DEBUG")) { 275 write(2, "->C:", 4); 276 write(2, h->rxq + h->rxlen - st, st); 277 } 195 int msn_handler(struct msn_data *h) 196 { 197 int st = 1; 278 198 279 199 while (st) { … … 287 207 288 208 cmd_text = g_strndup(h->rxq, i); 289 cmd = msn_linesplit(cmd_text); 290 for (count = 0; cmd[count]; count++) { 291 ; 292 } 293 st = h->exec_command(h, cmd, count); 209 cmd = g_strsplit_set(cmd_text, " ", -1); 210 count = g_strv_length(cmd); 211 212 st = msn_ns_command(h, cmd, count); 213 214 g_strfreev(cmd); 294 215 g_free(cmd_text); 295 216 … … 314 235 /* If we reached the end of the buffer, there's still an incomplete command there. 315 236 Return and wait for more data. */ 316 if (i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') {237 if (i && i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') { 317 238 break; 318 239 } … … 327 248 328 249 msg = g_strndup(h->rxq, h->msglen); 329 cmd = msn_linesplit(h->cmd_text); 330 for (count = 0; cmd[count]; count++) { 331 ; 332 } 333 334 st = h->exec_message(h, msg, h->msglen, cmd, count); 250 251 cmd = g_strsplit_set(h->cmd_text, " ", -1); 252 count = g_strv_length(cmd); 253 254 st = msn_ns_message(h, msg, h->msglen, cmd, count); 255 256 g_strfreev(cmd); 335 257 g_free(msg); 336 258 g_free(h->cmd_text); … … 366 288 } 367 289 368 void msn_msgq_purge(struct im_connection *ic, GSList **list)369 {370 struct msn_message *m;371 GString *ret;372 GSList *l;373 int n = 0;374 375 l = *list;376 if (l == NULL) {377 return;378 }379 380 m = l->data;381 ret = g_string_sized_new(1024);382 g_string_printf(ret, "Warning: Cleaning up MSN (switchboard) connection with unsent "383 "messages to %s:", m->who ? m->who : "unknown recipient");384 385 while (l) {386 m = l->data;387 388 if (strncmp(m->text, "\r\r\r", 3) != 0) {389 g_string_append_printf(ret, "\n%s", m->text);390 n++;391 }392 393 g_free(m->who);394 g_free(m->text);395 g_free(m);396 397 l = l->next;398 }399 g_slist_free(*list);400 *list = NULL;401 402 if (n > 0) {403 imcb_log(ic, "%s", ret->str);404 }405 g_string_free(ret, TRUE);406 }407 408 290 /* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ 409 291 char *msn_p11_challenge(char *challenge) … … 529 411 int msn_ns_set_display_name(struct im_connection *ic, const char *value) 530 412 { 531 struct msn_data *md = ic->proto_data; 532 char fn[strlen(value) * 3 + 1]; 533 534 strcpy(fn, value); 535 http_encode(fn); 536 537 /* Note: We don't actually know if the server accepted the new name, 538 and won't give proper feedback yet if it doesn't. */ 539 return msn_ns_write(ic, -1, "PRP %d MFN %s\r\n", ++md->trId, fn); 413 // TODO, implement this through msn_set_away's method 414 return 1; 540 415 } 541 416 -
protocols/msn/ns.c
r531eabd rb1dc403 35 35 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond); 36 36 static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond); 37 static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts);38 static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts);39 37 40 38 static void msn_ns_send_adl_start(struct im_connection *ic); 41 39 static void msn_ns_send_adl(struct im_connection *ic); 40 static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd); 41 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action); 42 static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put); 42 43 43 44 int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) … … 54 55 55 56 if (fd < 0) { 56 fd = md-> ns->fd;57 fd = md->fd; 57 58 } 58 59 59 60 if (getenv("BITLBEE_DEBUG")) { 60 fprintf(stderr, " ->NS%d:%s\n", fd, out);61 fprintf(stderr, "\x1b[91m>>>[NS%d] %s\n\x1b[97m", fd, out); 61 62 } 62 63 63 64 len = strlen(out); 64 st = write(fd, out, len); 65 66 if (md->is_http) { 67 st = len; 68 msn_gw_write(md->gw, out, len); 69 } else { 70 st = write(fd, out, len); 71 } 72 65 73 g_free(out); 66 74 if (st != len) { … … 73 81 } 74 82 75 gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port) 76 { 77 if (handler->fd >= 0) { 78 closesocket(handler->fd); 79 } 80 81 handler->exec_command = msn_ns_command; 82 handler->exec_message = msn_ns_message; 83 handler->data = ic; 84 handler->fd = proxy_connect(host, port, msn_ns_connected, handler); 85 if (handler->fd < 0) { 83 gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port) 84 { 85 struct msn_data *md = ic->proto_data; 86 87 if (md->fd >= 0) { 88 closesocket(md->fd); 89 } 90 91 if (md->is_http) { 92 md->gw = msn_gw_new(ic); 93 md->gw->callback = msn_ns_callback; 94 msn_ns_connected(md, -1, B_EV_IO_READ); 95 } else { 96 md->fd = proxy_connect(host, port, msn_ns_connected, md); 97 if (md->fd < 0) { 98 imcb_error(ic, "Could not connect to server"); 99 imc_logout(ic, TRUE); 100 return FALSE; 101 } 102 } 103 104 return TRUE; 105 } 106 107 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond) 108 { 109 struct msn_data *md = data; 110 struct im_connection *ic = md->ic; 111 112 if (source == -1 && !md->is_http) { 86 113 imcb_error(ic, "Could not connect to server"); 87 114 imc_logout(ic, TRUE); … … 89 116 } 90 117 91 return TRUE; 92 } 93 94 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond) 95 { 96 struct msn_handler_data *handler = data; 97 struct im_connection *ic = handler->data; 98 struct msn_data *md; 99 100 if (!g_slist_find(msn_connections, ic)) { 101 return FALSE; 102 } 103 104 md = ic->proto_data; 105 106 if (source == -1) { 107 imcb_error(ic, "Could not connect to server"); 108 imc_logout(ic, TRUE); 109 return FALSE; 110 } 111 112 g_free(handler->rxq); 113 handler->rxlen = 0; 114 handler->rxq = g_new0(char, 1); 118 g_free(md->rxq); 119 md->rxlen = 0; 120 md->rxq = g_new0(char, 1); 115 121 116 122 if (md->uuid == NULL) { … … 130 136 131 137 if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER)) { 132 handler->inpa = b_input_add(handler->fd, B_EV_IO_READ, msn_ns_callback, handler); 138 if (!md->is_http) { 139 md->inpa = b_input_add(md->fd, B_EV_IO_READ, msn_ns_callback, md); 140 } 133 141 imcb_log(ic, "Connected to server, waiting for reply"); 134 142 } … … 137 145 } 138 146 139 void msn_ns_close(struct msn_handler_data *handler) 140 { 141 if (handler->fd >= 0) { 142 closesocket(handler->fd); 143 b_event_remove(handler->inpa); 144 } 145 146 handler->fd = handler->inpa = -1; 147 g_free(handler->rxq); 148 g_free(handler->cmd_text); 149 150 handler->rxlen = 0; 151 handler->rxq = NULL; 152 handler->cmd_text = NULL; 147 void msn_ns_close(struct msn_data *md) 148 { 149 if (md->gw) { 150 msn_gw_free(md->gw); 151 } 152 if (md->fd >= 0) { 153 closesocket(md->fd); 154 b_event_remove(md->inpa); 155 } 156 157 md->fd = md->inpa = -1; 158 g_free(md->rxq); 159 g_free(md->cmd_text); 160 161 md->rxlen = 0; 162 md->rxq = NULL; 163 md->cmd_text = NULL; 153 164 } 154 165 155 166 static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond) 156 167 { 157 struct msn_handler_data *handler = data; 158 struct im_connection *ic = handler->data; 159 160 if (msn_handler(handler) == -1) { /* Don't do this on ret == 0, it's already done then. */ 168 struct msn_data *md = data; 169 struct im_connection *ic = md->ic; 170 char *bytes; 171 int st; 172 173 if (md->is_http) { 174 st = msn_gw_read(md->gw, &bytes); 175 } else { 176 bytes = g_malloc(1024); 177 st = read(md->fd, bytes, 1024); 178 } 179 180 if (st <= 0) { 161 181 imcb_error(ic, "Error while reading from server"); 162 182 imc_logout(ic, TRUE); 163 164 183 return FALSE; 165 } else { 166 return TRUE; 167 } 168 } 169 170 static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts) 171 { 172 struct im_connection *ic = handler->data; 173 struct msn_data *md = ic->proto_data; 184 } 185 186 msn_queue_feed(md, bytes, st); 187 188 g_free(bytes); 189 190 /* Ignore ret == 0, it's already disconnected then. */ 191 msn_handler(md); 192 193 return TRUE; 194 195 } 196 197 int msn_ns_command(struct msn_data *md, char **cmd, int num_parts) 198 { 199 struct im_connection *ic = md->ic; 174 200 175 201 if (num_parts == 0) { … … 185 211 } 186 212 187 return(msn_ns_write(ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",213 return(msn_ns_write(ic, md->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s VmVyc2lvbjogMQ0KWGZyQ291bnQ6IDINClhmclNlbnRVVENUaW1lOiA2MzU2MTQ3OTU5NzgzOTAwMDANCklzR2VvWGZyOiB0cnVlDQo=\r\n", 188 214 ++md->trId, ic->acc->user)); 189 215 } else if (strcmp(cmd[0], "CVR") == 0) { 190 216 /* We don't give a damn about the information we just received */ 191 return msn_ns_write(ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);217 return msn_ns_write(ic, md->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user); 192 218 } else if (strcmp(cmd[0], "XFR") == 0) { 193 219 char *server; … … 195 221 196 222 if (num_parts >= 6 && strcmp(cmd[2], "NS") == 0) { 197 b_event_remove( handler->inpa);198 handler->inpa = -1;223 b_event_remove(md->inpa); 224 md->inpa = -1; 199 225 200 226 server = strchr(cmd[3], ':'); … … 209 235 210 236 imcb_log(ic, "Transferring to other server"); 211 return msn_ns_connect(ic, handler, server, port); 212 } else if (num_parts >= 6 && strcmp(cmd[2], "SB") == 0) { 213 struct msn_switchboard *sb; 214 215 server = strchr(cmd[3], ':'); 216 if (!server) { 217 imcb_error(ic, "Syntax error"); 218 imc_logout(ic, TRUE); 219 return(0); 220 } 221 *server = 0; 222 port = atoi(server + 1); 223 server = cmd[3]; 224 225 if (strcmp(cmd[4], "CKI") != 0) { 226 imcb_error(ic, "Unknown authentication method for switchboard"); 227 imc_logout(ic, TRUE); 228 return(0); 229 } 230 231 debug("Connecting to a new switchboard with key %s", cmd[5]); 232 233 if ((sb = msn_sb_create(ic, server, port, cmd[5], MSN_SB_NEW)) == NULL) { 234 /* Although this isn't strictly fatal for the NS connection, it's 235 definitely something serious (we ran out of file descriptors?). */ 236 imcb_error(ic, "Could not create new switchboard"); 237 imc_logout(ic, TRUE); 238 return(0); 239 } 240 241 if (md->msgq) { 242 struct msn_message *m = md->msgq->data; 243 GSList *l; 244 245 sb->who = g_strdup(m->who); 246 247 /* Move all the messages to the first user in the message 248 queue to the switchboard message queue. */ 249 l = md->msgq; 250 while (l) { 251 m = l->data; 252 l = l->next; 253 if (strcmp(m->who, sb->who) == 0) { 254 sb->msgq = g_slist_append(sb->msgq, m); 255 md->msgq = g_slist_remove(md->msgq, m); 256 } 257 } 258 } 237 return msn_ns_connect(ic, server, port); 259 238 } else { 260 239 imcb_error(ic, "Syntax error"); … … 290 269 } 291 270 292 handler->msglen = atoi(cmd[3]);293 294 if ( handler->msglen <= 0) {271 md->msglen = atoi(cmd[3]); 272 273 if (md->msglen <= 0) { 295 274 imcb_error(ic, "Syntax error"); 296 275 imc_logout(ic, TRUE); 297 276 return(0); 298 277 } 299 } else if (strcmp(cmd[0], "BLP") == 0) {300 msn_ns_send_adl_start(ic);301 return msn_ns_finish_login(ic);302 278 } else if (strcmp(cmd[0], "ADL") == 0) { 303 279 if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) { … … 305 281 return msn_ns_finish_login(ic); 306 282 } else if (num_parts >= 3) { 307 handler->msglen = atoi(cmd[2]); 308 } 309 } else if (strcmp(cmd[0], "PRP") == 0) { 310 imcb_connected(ic); 283 md->msglen = atoi(cmd[2]); 284 } 311 285 } else if (strcmp(cmd[0], "CHL") == 0) { 312 286 char *resp; … … 326 300 g_free(resp); 327 301 return st; 328 } else if (strcmp(cmd[0], "ILN") == 0 || strcmp(cmd[0], "NLN") == 0) { 329 const struct msn_away_state *st; 330 const char *handle; 331 int cap = 0; 332 333 if (num_parts < 6) { 334 imcb_error(ic, "Syntax error"); 335 imc_logout(ic, TRUE); 336 return(0); 337 } 338 /* ILN and NLN are more or less the same, except ILN has a trId 339 at the start, and NLN has a capability field at the end. 340 Does ILN still exist BTW? */ 341 if (cmd[0][1] == 'I') { 342 cmd++; 343 } else { 344 cap = atoi(cmd[4]); 345 } 346 347 handle = msn_normalize_handle(cmd[2]); 348 if (strcmp(handle, ic->acc->user) == 0) { 349 return 1; /* That's me! */ 350 351 } 352 http_decode(cmd[3]); 353 imcb_rename_buddy(ic, handle, cmd[3]); 354 355 st = msn_away_state_by_code(cmd[1]); 356 if (!st) { 357 /* FIXME: Warn/Bomb about unknown away state? */ 358 st = msn_away_state_list + 1; 359 } 360 361 imcb_buddy_status(ic, handle, OPT_LOGGED_IN | 362 (st != msn_away_state_list ? OPT_AWAY : 0) | 363 (cap & 1 ? OPT_MOBILE : 0), 364 st->name, NULL); 365 366 msn_sb_stop_keepalives(msn_sb_by_handle(ic, handle)); 367 } else if (strcmp(cmd[0], "FLN") == 0) { 368 const char *handle; 369 370 if (cmd[1] == NULL) { 371 return 1; 372 } 373 374 handle = msn_normalize_handle(cmd[1]); 375 imcb_buddy_status(ic, handle, 0, NULL, NULL); 376 msn_sb_start_keepalives(msn_sb_by_handle(ic, handle), TRUE); 377 } else if (strcmp(cmd[0], "RNG") == 0) { 378 struct msn_switchboard *sb; 379 char *server; 380 int session, port; 381 382 if (num_parts < 7) { 383 imcb_error(ic, "Syntax error"); 384 imc_logout(ic, TRUE); 385 return(0); 386 } 387 388 session = atoi(cmd[1]); 389 390 server = strchr(cmd[2], ':'); 391 if (!server) { 392 imcb_error(ic, "Syntax error"); 393 imc_logout(ic, TRUE); 394 return(0); 395 } 396 *server = 0; 397 port = atoi(server + 1); 398 server = cmd[2]; 399 400 if (strcmp(cmd[3], "CKI") != 0) { 401 imcb_error(ic, "Unknown authentication method for switchboard"); 402 imc_logout(ic, TRUE); 403 return(0); 404 } 405 406 debug("Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4]); 407 408 if ((sb = msn_sb_create(ic, server, port, cmd[4], session)) == NULL) { 409 /* Although this isn't strictly fatal for the NS connection, it's 410 definitely something serious (we ran out of file descriptors?). */ 411 imcb_error(ic, "Could not create new switchboard"); 412 imc_logout(ic, TRUE); 413 return(0); 414 } else { 415 sb->who = g_strdup(msn_normalize_handle(cmd[5])); 416 } 302 } else if (strcmp(cmd[0], "QRY") == 0) { 303 /* CONGRATULATIONS */ 417 304 } else if (strcmp(cmd[0], "OUT") == 0) { 418 int allow_reconnect = TRUE; 419 420 if (cmd[1] && strcmp(cmd[1], "OTH") == 0) { 421 imcb_error(ic, "Someone else logged in with your account"); 422 allow_reconnect = FALSE; 423 } else if (cmd[1] && strcmp(cmd[1], "SSD") == 0) { 424 imcb_error(ic, "Terminating session because of server shutdown"); 425 } else { 426 imcb_error(ic, "Session terminated by remote server (%s)", 427 cmd[1] ? cmd[1] : "reason unknown)"); 428 } 429 430 imc_logout(ic, allow_reconnect); 305 imcb_error(ic, "Session terminated by remote server (%s)", cmd[1] ? cmd[1] : "reason unknown"); 306 imc_logout(ic, TRUE); 431 307 return(0); 432 } else if (strcmp(cmd[0], "IPG") == 0) { 433 imcb_error(ic, "Received IPG command, we don't handle them yet."); 434 435 handler->msglen = atoi(cmd[1]); 436 437 if (handler->msglen <= 0) { 438 imcb_error(ic, "Syntax error"); 439 imc_logout(ic, TRUE); 440 return(0); 441 } 442 } 443 #if 0 444 else if (strcmp(cmd[0], "ADG") == 0) { 445 char *group = g_strdup(cmd[3]); 446 int groupnum, i; 447 GSList *l, *next; 448 449 http_decode(group); 450 if (sscanf(cmd[4], "%d", &groupnum) == 1) { 451 if (groupnum >= md->groupcount) { 452 md->grouplist = g_renew(char *, md->grouplist, groupnum + 1); 453 for (i = md->groupcount; i <= groupnum; i++) { 454 md->grouplist[i] = NULL; 455 } 456 md->groupcount = groupnum + 1; 457 } 458 g_free(md->grouplist[groupnum]); 459 md->grouplist[groupnum] = group; 460 } else { 461 /* Shouldn't happen, but if it does, give up on the group. */ 462 g_free(group); 463 imcb_error(ic, "Syntax error"); 464 imc_logout(ic, TRUE); 465 return 0; 466 } 467 468 for (l = md->grpq; l; l = next) { 469 struct msn_groupadd *ga = l->data; 470 next = l->next; 471 if (g_strcasecmp(ga->group, group) == 0) { 472 if (!msn_buddy_list_add(ic, "FL", ga->who, ga->who, group)) { 473 return 0; 474 } 475 476 g_free(ga->group); 477 g_free(ga->who); 478 g_free(ga); 479 md->grpq = g_slist_remove(md->grpq, ga); 480 } 481 } 482 } 483 #endif 484 else if (strcmp(cmd[0], "GCF") == 0) { 308 } else if (strcmp(cmd[0], "GCF") == 0) { 485 309 /* Coming up is cmd[2] bytes of stuff we're supposed to 486 310 censore. Meh. */ 487 handler->msglen = atoi(cmd[2]); 488 } else if (strcmp(cmd[0], "UBX") == 0) { 489 /* Status message. */ 311 md->msglen = atoi(cmd[2]); 312 } else if ((strcmp(cmd[0], "NFY") == 0) || (strcmp(cmd[0], "SDG") == 0)) { 490 313 if (num_parts >= 3) { 491 handler->msglen = atoi(cmd[2]); 314 md->msglen = atoi(cmd[2]); 315 } 316 } else if (strcmp(cmd[0], "PUT") == 0) { 317 if (num_parts >= 4) { 318 md->msglen = atoi(cmd[3]); 492 319 } 493 320 } else if (strcmp(cmd[0], "NOT") == 0) { 494 /* Some kind of notification, poorly documented but495 apparently used to announce address book changes. */496 321 if (num_parts >= 2) { 497 handler->msglen = atoi(cmd[1]); 498 } 499 } else if (strcmp(cmd[0], "UBM") == 0) { 500 if (num_parts >= 7) { 501 handler->msglen = atoi(cmd[6]); 322 md->msglen = atoi(cmd[1]); 502 323 } 503 324 } else if (strcmp(cmd[0], "QNG") == 0) { … … 516 337 /* Oh yes, errors can have payloads too now. Discard them for now. */ 517 338 if (num_parts >= 3) { 518 handler->msglen = atoi(cmd[2]);339 md->msglen = atoi(cmd[2]); 519 340 } 520 341 } else { 521 /* debug( "Received unknown command from main server: %s", cmd[0] ); */342 imcb_error(ic, "Received unknown command from main server: %s", cmd[0]); 522 343 } 523 344 … … 525 346 } 526 347 527 static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts)528 { 529 struct im_connection *ic = handler->data;348 int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts) 349 { 350 struct im_connection *ic = md->ic; 530 351 char *body; 531 352 int blen = 0; … … 598 419 } 599 420 } else if (g_strncasecmp(ct, "text/x-msmsgsactivemailnotification", 35) == 0) { 600 } else if (g_strncasecmp(ct, "text/x-msmsgsinitialmdatanotification", 37) == 0 || 601 g_strncasecmp(ct, "text/x-msmsgsoimnotification", 28) == 0) { 602 /* We received an offline message. Or at least notification 603 that there is one waiting for us. Fetching the message(s) 604 and purging them from the server is a lot of SOAPy work 605 not worth doing IMHO. Also I thought it was possible to 606 have the notification server send them directly, I was 607 pretty sure I saw Pidgin do it.. 608 609 At least give a notification for now, seems like a 610 reasonable thing to do. Only problem is, they'll keep 611 coming back at login time until you read them using a 612 different client. :-( */ 613 614 char *xml = get_rfc822_header(body, "Mail-Data:", blen); 615 struct xt_node *md, *m; 616 617 if (!xml) { 618 return 1; 619 } 620 md = xt_from_string(xml, 0); 621 if (!md) { 622 return 1; 623 } 624 625 for (m = md->children; (m = xt_find_node(m, "M")); m = m->next) { 626 struct xt_node *e = xt_find_node(m->children, "E"); 627 struct xt_node *rt = xt_find_node(m->children, "RT"); 628 struct tm tp; 629 time_t msgtime = 0; 630 631 if (!e || !e->text) { 632 continue; 633 } 634 635 memset(&tp, 0, sizeof(tp)); 636 if (rt && rt->text && 637 sscanf(rt->text, "%4d-%2d-%2dT%2d:%2d:%2d.", 638 &tp.tm_year, &tp.tm_mon, &tp.tm_mday, 639 &tp.tm_hour, &tp.tm_min, &tp.tm_sec) == 6) { 640 tp.tm_year -= 1900; 641 tp.tm_mon--; 642 msgtime = mktime_utc(&tp); 643 644 } 645 imcb_buddy_msg(ic, e->text, 646 "<< \002BitlBee\002 - Received offline message. BitlBee can't show these. >>", 0, 647 msgtime); 648 } 649 650 g_free(xml); 651 xt_free_node(md); 421 /* Notification that a message has been read... Ignore it */ 652 422 } else { 653 423 debug("Can't handle %s packet from notification server", ct); … … 656 426 g_free(ct); 657 427 } 658 } else if (strcmp(cmd[0], "UBX") == 0) {659 struct xt_node *ubx, *psm;660 char *psm_text = NULL;661 662 ubx = xt_from_string(msg, msglen);663 if (ubx && strcmp(ubx->name, "Data") == 0 &&664 (psm = xt_find_node(ubx->children, "PSM"))) {665 psm_text = psm->text;666 }667 668 imcb_buddy_status_msg(ic, msn_normalize_handle(cmd[1]), psm_text);669 xt_free_node(ubx);670 428 } else if (strcmp(cmd[0], "ADL") == 0) { 671 429 struct xt_node *adl, *d, *c; … … 716 474 } 717 475 } 718 } else if (strcmp(cmd[0], "UBM") == 0) { 719 /* This one will give us msgs from federated networks. Technically 720 it should also get us offline messages, but I don't know how 721 I can signal MSN servers to use it. */ 722 char *ct, *handle; 723 724 if (strcmp(cmd[1], ic->acc->user) == 0) { 725 /* With MPOP, you'll get copies of your own msgs from other 726 sessions. Discard those at least for now. */ 727 return 1; 728 } 729 730 ct = get_rfc822_header(msg, "Content-Type", msglen); 731 if (strncmp(ct, "text/plain", 10) != 0) { 732 /* Typing notification or something? */ 733 g_free(ct); 734 return 1; 735 } 736 if (strcmp(cmd[2], "1") != 0) { 737 handle = g_strdup_printf("%s:%s", cmd[2], cmd[1]); 738 } else { 739 handle = g_strdup(cmd[1]); 740 } 741 742 imcb_buddy_msg(ic, handle, body, 0, 0); 743 g_free(handle); 476 } else if ((strcmp(cmd[0], "SDG") == 0) || (strcmp(cmd[0], "NFY") == 0)) { 477 msn_ns_structured_message(md, msg, msglen, cmd); 744 478 } 745 479 746 480 return 1; 481 } 482 483 static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd) 484 { 485 char **parts = NULL; 486 char *semicolon = NULL; 487 char *action = NULL; 488 char *from = NULL; 489 char *who = NULL; 490 491 parts = g_strsplit(msg, "\r\n\r\n", 4); 492 493 if (!(from = get_rfc822_header(parts[0], "From", 0))) { 494 goto cleanup; 495 } 496 497 /* either the semicolon or the end of the string */ 498 semicolon = strchr(from, ';') ? : (from + strlen(from)); 499 500 who = g_strndup(from + 2, semicolon - from - 2); 501 502 if ((strcmp(cmd[0], "SDG") == 0) && (action = get_rfc822_header(parts[2], "Message-Type", 0))) { 503 msn_ns_sdg(md, who, parts, action); 504 505 } else if ((strcmp(cmd[0], "NFY") == 0) && (action = get_rfc822_header(parts[2], "Uri", 0))) { 506 gboolean is_put = (strcmp(cmd[1], "PUT") == 0); 507 msn_ns_nfy(md, who, parts, action, is_put); 508 } 509 510 cleanup: 511 g_strfreev(parts); 512 g_free(action); 513 g_free(from); 514 g_free(who); 515 } 516 517 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action) 518 { 519 struct im_connection *ic = md->ic; 520 521 if (strcmp(action, "Control/Typing") == 0) { 522 imcb_buddy_typing(ic, who, OPT_TYPING); 523 } else if (strcmp(action, "Text") == 0) { 524 imcb_buddy_msg(ic, who, parts[3], 0, 0); 525 } 526 } 527 528 static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put) 529 { 530 struct im_connection *ic = md->ic; 531 struct xt_node *body = NULL; 532 struct xt_node *s = NULL; 533 const char *state = NULL; 534 char *nick = NULL; 535 char *psm = NULL; 536 int flags = OPT_LOGGED_IN; 537 538 if (strcmp(action, "/user") != 0) { 539 return; 540 } 541 542 if (!(body = xt_from_string(parts[3], 0))) { 543 goto cleanup; 544 } 545 546 s = body->children; 547 while ((s = xt_find_node(s, "s"))) { 548 struct xt_node *s2; 549 char *n = xt_find_attr(s, "n"); /* service name: IM, PE, etc */ 550 551 if (strcmp(n, "IM") == 0) { 552 /* IM has basic presence information */ 553 if (!is_put) { 554 /* NFY DEL with a <s> usually means log out from the last endpoint */ 555 flags &= ~OPT_LOGGED_IN; 556 break; 557 } 558 559 s2 = xt_find_node(s->children, "Status"); 560 if (s2 && s2->text_len) { 561 const struct msn_away_state *msn_state = msn_away_state_by_code(s2->text); 562 state = msn_state->name; 563 if (msn_state != msn_away_state_list) { 564 flags |= OPT_AWAY; 565 } 566 } 567 } else if (strcmp(n, "PE") == 0) { 568 if ((s2 = xt_find_node(s->children, "PSM")) && s2->text_len) { 569 psm = s2->text; 570 } 571 if ((s2 = xt_find_node(s->children, "FriendlyName")) && s2->text_len) { 572 nick = s2->text; 573 } 574 } 575 s = s->next; 576 } 577 578 imcb_buddy_status(ic, who, flags, state, psm); 579 580 if (nick) { 581 imcb_rename_buddy(ic, who, nick); 582 } 583 584 cleanup: 585 xt_free_node(body); 747 586 } 748 587 … … 768 607 void msn_auth_got_contact_list(struct im_connection *ic) 769 608 { 770 struct msn_data *md;771 772 609 /* Dead connection? */ 773 610 if (g_slist_find(msn_connections, ic) == NULL) { … … 775 612 } 776 613 777 m d = ic->proto_data;778 msn_ns_ write(ic, -1, "BLP %d %s\r\n", ++md->trId, "BL");614 msn_ns_send_adl_start(ic); 615 msn_ns_finish_login(ic); 779 616 } 780 617 781 618 static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data) 782 619 { 783 struct xt_node *adl = data, *d, *c ;620 struct xt_node *adl = data, *d, *c, *s; 784 621 struct bee_user *bu = value; 785 622 struct msn_buddy_data *bd = bu->data; … … 810 647 c = xt_new_node("c", NULL, NULL); 811 648 xt_add_attr(c, "n", handle); 812 xt_add_attr(c, "l", l);813 649 xt_add_attr(c, "t", "1"); /* FIXME: Network type, i.e. 32 for Y!MSG */ 650 s = xt_new_node("s", NULL, NULL); 651 xt_add_attr(s, "n", "IM"); 652 xt_add_attr(s, "l", l); 653 xt_insert_child(c, s); 814 654 xt_insert_child(d, c); 815 655 … … 881 721 882 722 if ((md->flags & MSN_DONE_ADL) && (md->flags & MSN_GOT_PROFILE)) { 883 if (md->flags & MSN_EMAIL_UNVERIFIED) { 884 imcb_connected(ic); 885 } else { 886 return msn_ns_set_display_name(ic, set_getstr(&ic->acc->set, "display_name")); 887 } 723 imcb_connected(ic); 888 724 } 889 725 … … 891 727 } 892 728 729 // TODO: typing notifications, nudges lol, etc 893 730 int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text) 894 731 { 895 732 struct msn_data *md = ic->proto_data; 896 int type= 0;897 char *buf , *handle;733 int retval = 0; 734 char *buf; 898 735 899 736 if (strncmp(text, "\r\r\r", 3) == 0) { … … 903 740 } 904 741 905 /* This might be a federated contact. Get its network number, 906 prefixed to bu->handle with a colon. Default is 1. */ 907 for (handle = bu->handle; g_ascii_isdigit(*handle); handle++) { 908 type = type * 10 + *handle - '0'; 909 } 910 if (*handle == ':') { 911 handle++; 912 } else { 913 type = 1; 914 } 915 916 buf = g_strdup_printf("%s%s", MSN_MESSAGE_HEADERS, text); 917 918 if (msn_ns_write(ic, -1, "UUM %d %s %d %d %zd\r\n%s", 919 ++md->trId, handle, type, 920 1, /* type == IM (not nudge/typing) */ 921 strlen(buf), buf)) { 922 return 1; 923 } else { 924 return 0; 925 } 926 } 927 928 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq) 929 { 930 GSList *l; 931 932 for (l = *msgq; l; l = l->next) { 933 struct msn_message *m = l->data; 934 bee_user_t *bu = bee_user_by_handle(ic->bee, ic, m->who); 935 936 if (bu) { 937 if (!msn_ns_sendmessage(ic, bu, m->text)) { 938 return; 939 } 940 } 941 } 942 943 while (*msgq != NULL) { 944 struct msn_message *m = (*msgq)->data; 945 946 g_free(m->who); 947 g_free(m->text); 948 g_free(m); 949 950 *msgq = g_slist_remove(*msgq, m); 951 } 952 } 742 buf = g_strdup_printf(MSN_MESSAGE_HEADERS, bu->handle, ic->acc->user, md->uuid, strlen(text), text); 743 retval = msn_ns_write(ic, -1, "SDG %d %zd\r\n%s", ++md->trId, strlen(buf), buf); 744 g_free(buf); 745 return retval; 746 } -
protocols/msn/soap.c
r531eabd rb1dc403 209 209 return; 210 210 } 211 fprintf(stderr, "\n\x1b[90mSOAP:\n"); 211 212 212 213 if (headers) { … … 225 226 xt_free_node(xt); 226 227 } 228 fprintf(stderr, "\n\x1b[97m\n"); 227 229 } 228 230 -
protocols/msn/soap.h
r531eabd rb1dc403 167 167 168 168 #define SOAP_MEMLIST_PAYLOAD \ 169 "<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\"><serviceFilter xmlns=\"http://www.msn.com/webservices/AddressBook\"><Types xmlns=\"http://www.msn.com/webservices/AddressBook\"><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Messenger</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Invitation</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">SocialNetwork</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Space</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Profile</ServiceType></Types></serviceFilter>" \169 "<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\"><serviceFilter><Types><ServiceType>Messenger</ServiceType><ServiceType>IMAvailability</ServiceType></Types></serviceFilter><expandMembership>true</expandMembership>" \ 170 170 "</FindMembership>" 171 171 -
protocols/msn/tables.c
r531eabd rb1dc403 73 73 { 206, "Domain name missing", 0 }, 74 74 { 207, "Already logged in", 0 }, 75 { 208, "Invalid handle", STATUS_SB_IM_SPARE},75 { 208, "Invalid handle", 0 }, 76 76 { 209, "Forbidden nickname", 0 }, 77 77 { 210, "Buddy list too long", 0 }, 78 78 { 215, "Handle is already in list", 0 }, 79 { 216, "Handle is not in list", STATUS_SB_IM_SPARE},80 { 217, "Person is off-line or non-existent", STATUS_SB_IM_SPARE},79 { 216, "Handle is not in list", 0 }, 80 { 217, "Person is off-line or non-existent", 0 }, 81 81 { 218, "Already in that mode", 0 }, 82 82 { 219, "Handle is already in opposite list", 0 }, … … 113 113 { 711, "Write is blocking", STATUS_FATAL }, 114 114 { 712, "Session is overloaded", STATUS_FATAL }, 115 { 713, "Calling too rapidly", STATUS_SB_IM_SPARE},115 { 713, "Calling too rapidly", 0 }, 116 116 { 714, "Too many sessions", STATUS_FATAL }, 117 117 { 715, "Not expected/Invalid argument/action", 0 }, -
protocols/nogaim.c
r531eabd rb1dc403 503 503 }; 504 504 505 static void imcb_ask_ auth_cb_no(void *data)505 static void imcb_ask_cb_free(void *data) 506 506 { 507 507 struct imcb_ask_cb_data *cbd = data; 508 509 cbd->ic->acc->prpl->auth_deny(cbd->ic, cbd->handle);510 508 511 509 g_free(cbd->handle); … … 513 511 } 514 512 513 static void imcb_ask_auth_cb_no(void *data) 514 { 515 struct imcb_ask_cb_data *cbd = data; 516 517 cbd->ic->acc->prpl->auth_deny(cbd->ic, cbd->handle); 518 519 imcb_ask_cb_free(cbd); 520 } 521 515 522 static void imcb_ask_auth_cb_yes(void *data) 516 523 { … … 519 526 cbd->ic->acc->prpl->auth_allow(cbd->ic, cbd->handle); 520 527 521 g_free(cbd->handle); 522 g_free(cbd); 528 imcb_ask_cb_free(cbd); 523 529 } 524 530 … … 540 546 data->handle = g_strdup(handle); 541 547 query_add((irc_t *) ic->bee->ui_data, ic, s, 542 imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, g_free, data); 543 } 544 545 546 static void imcb_ask_add_cb_no(void *data) 547 { 548 g_free(((struct imcb_ask_cb_data*) data)->handle); 549 g_free(data); 548 imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, imcb_ask_cb_free, data); 549 550 g_free(s); 550 551 } 551 552 … … 556 557 cbd->ic->acc->prpl->add_buddy(cbd->ic, cbd->handle, NULL); 557 558 558 imcb_ask_ add_cb_no(data);559 imcb_ask_cb_free(data); 559 560 } 560 561 561 562 void imcb_ask_add(struct im_connection *ic, const char *handle, const char *realname) 562 563 { 563 struct imcb_ask_cb_data *data = g_new0(struct imcb_ask_cb_data, 1);564 struct imcb_ask_cb_data *data; 564 565 char *s; 565 566 … … 569 570 } 570 571 572 data = g_new0(struct imcb_ask_cb_data, 1); 573 571 574 s = g_strdup_printf("The user %s is not in your buddy list yet. Do you want to add him/her now?", handle); 572 575 … … 574 577 data->handle = g_strdup(handle); 575 578 query_add((irc_t *) ic->bee->ui_data, ic, s, 576 imcb_ask_add_cb_yes, imcb_ask_add_cb_no, g_free, data); 579 imcb_ask_add_cb_yes, imcb_ask_cb_free, imcb_ask_cb_free, data); 580 581 g_free(s); 577 582 } 578 583 -
protocols/purple/ft-direct.c
r531eabd rb1dc403 28 28 29 29 #include "bitlbee.h" 30 #include "bpurple.h" 30 31 31 32 #include <stdarg.h> … … 207 208 void purple_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *handle) 208 209 { 209 PurpleAccount *pa= ic->proto_data;210 struct purple_data *pd = ic->proto_data; 210 211 struct prpl_xfer_data *px; 211 212 … … 213 214 multi-threaded anyway. */ 214 215 next_ft = ft; 215 serv_send_file(purple_account_get_connection(pa), handle, ft->file_name); 216 serv_send_file(purple_account_get_connection(pd->account), handle, 217 ft->file_name); 216 218 217 219 ft->write = prpl_xfer_write; -
protocols/purple/ft.c
r531eabd rb1dc403 28 28 29 29 #include "bitlbee.h" 30 #include "bpurple.h" 30 31 31 32 #include <stdarg.h> … … 285 286 { 286 287 struct prpl_xfer_data *px = ft->data; 287 PurpleAccount *pa= px->ic->proto_data;288 struct purple_data *pd = px->ic->proto_data; 288 289 289 290 /* xfer_new() will pick up this variable. It's a hack but we're not 290 291 multi-threaded anyway. */ 291 292 next_ft = ft; 292 serv_send_file(purple_account_get_connection(pa), px->handle, px->fn); 293 serv_send_file(purple_account_get_connection(pd->account), 294 px->handle, px->fn); 293 295 } 294 296 -
protocols/purple/purple.c
r531eabd rb1dc403 23 23 24 24 #include "bitlbee.h" 25 #include "bpurple.h" 25 26 #include "help.h" 26 27 … … 39 40 static char *set_eval_display_name(set_t *set, char *value); 40 41 42 void purple_request_input_callback(guint id, struct im_connection *ic, 43 const char *message, const char *who); 44 45 /* purple_request_input specific stuff */ 46 typedef void (*ri_callback_t)(gpointer, const gchar *); 47 48 struct request_input_data { 49 ri_callback_t data_callback; 50 void *user_data; 51 struct im_connection *ic; 52 char *buddy; 53 guint id; 54 }; 55 41 56 struct im_connection *purple_ic_by_pa(PurpleAccount *pa) 42 57 { 43 58 GSList *i; 59 struct purple_data *pd; 44 60 45 61 for (i = purple_connections; i; i = i->next) { 46 if (((struct im_connection *) i->data)->proto_data == pa) { 62 pd = ((struct im_connection *) i->data)->proto_data; 63 if (pd->account == pa) { 47 64 return i->data; 48 65 } … … 290 307 { 291 308 struct im_connection *ic = imcb_new(acc); 292 PurpleAccount *pa;309 struct purple_data *pd; 293 310 294 311 if ((local_bee != NULL && local_bee != acc->bee) || … … 306 323 purple_connections = g_slist_prepend(purple_connections, ic); 307 324 308 ic->proto_data = pa = purple_account_new(acc->user, (char *) acc->prpl->data); 309 purple_account_set_password(pa, acc->pass); 310 purple_sync_settings(acc, pa); 311 312 purple_account_set_enabled(pa, "BitlBee", TRUE); 325 ic->proto_data = pd = g_new0(struct purple_data, 1); 326 pd->account = purple_account_new(acc->user, (char *) acc->prpl->data); 327 pd->input_requests = g_hash_table_new_full(g_direct_hash, g_direct_equal, 328 NULL, g_free); 329 pd->next_request_id = 0; 330 purple_account_set_password(pd->account, acc->pass); 331 purple_sync_settings(acc, pd->account); 332 333 purple_account_set_enabled(pd->account, "BitlBee", TRUE); 313 334 } 314 335 315 336 static void purple_logout(struct im_connection *ic) 316 337 { 317 PurpleAccount *pa = ic->proto_data; 318 319 purple_account_set_enabled(pa, "BitlBee", FALSE); 338 struct purple_data *pd = ic->proto_data; 339 340 if (!pd) { 341 return; 342 } 343 344 purple_account_set_enabled(pd->account, "BitlBee", FALSE); 320 345 purple_connections = g_slist_remove(purple_connections, ic); 321 purple_accounts_remove(pa); 346 purple_accounts_remove(pd->account); 347 g_hash_table_destroy(pd->input_requests); 348 g_free(pd); 322 349 } 323 350 … … 325 352 { 326 353 PurpleConversation *conv; 354 struct purple_data *pd = ic->proto_data; 355 356 if (!strncmp(who, PURPLE_REQUEST_HANDLE, sizeof(PURPLE_REQUEST_HANDLE) - 1)) { 357 guint request_id = atoi(who + sizeof(PURPLE_REQUEST_HANDLE)); 358 purple_request_input_callback(request_id, ic, message, who); 359 return 1; 360 } 327 361 328 362 if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, 329 who, ic->proto_data)) == NULL) {363 who, pd->account)) == NULL) { 330 364 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, 331 ic->proto_data, who);365 pd->account, who); 332 366 } 333 367 … … 339 373 static GList *purple_away_states(struct im_connection *ic) 340 374 { 341 PurpleAccount *pa= ic->proto_data;375 struct purple_data *pd = ic->proto_data; 342 376 GList *st, *ret = NULL; 343 377 344 for (st = purple_account_get_status_types(p a); st; st = st->next) {378 for (st = purple_account_get_status_types(pd->account); st; st = st->next) { 345 379 PurpleStatusPrimitive prim = purple_status_type_get_primitive(st->data); 346 380 if (prim != PURPLE_STATUS_AVAILABLE && prim != PURPLE_STATUS_OFFLINE) { … … 354 388 static void purple_set_away(struct im_connection *ic, char *state_txt, char *message) 355 389 { 356 PurpleAccount *pa= ic->proto_data;357 GList *status_types = purple_account_get_status_types(p a), *st;390 struct purple_data *pd = ic->proto_data; 391 GList *status_types = purple_account_get_status_types(pd->account), *st; 358 392 PurpleStatusType *pst = NULL; 359 393 GList *args = NULL; … … 378 412 } 379 413 380 purple_account_set_status_list(pa, st ? purple_status_type_get_id(pst) : "away", 414 purple_account_set_status_list(pd->account, 415 st ? purple_status_type_get_id(pst) : "away", 381 416 TRUE, args); 382 417 … … 447 482 PurpleBuddy *pb; 448 483 PurpleGroup *pg = NULL; 484 struct purple_data *pd = ic->proto_data; 449 485 450 486 if (group && !(pg = purple_find_group(group))) { … … 453 489 } 454 490 455 pb = purple_buddy_new( (PurpleAccount *) ic->proto_data, who, NULL);491 pb = purple_buddy_new(pd->account, who, NULL); 456 492 purple_blist_add_buddy(pb, NULL, pg, NULL); 457 purple_account_add_buddy( (PurpleAccount *) ic->proto_data, pb);458 459 purple_gg_buddylist_export( ((PurpleAccount *) ic->proto_data)->gc);493 purple_account_add_buddy(pd->account, pb); 494 495 purple_gg_buddylist_export(pd->account->gc); 460 496 } 461 497 … … 463 499 { 464 500 PurpleBuddy *pb; 465 466 pb = purple_find_buddy((PurpleAccount *) ic->proto_data, who); 501 struct purple_data *pd = ic->proto_data; 502 503 pb = purple_find_buddy(pd->account, who); 467 504 if (pb != NULL) { 468 505 PurpleGroup *group; 469 506 470 507 group = purple_buddy_get_group(pb); 471 purple_account_remove_buddy( (PurpleAccount *) ic->proto_data, pb, group);508 purple_account_remove_buddy(pd->account, pb, group); 472 509 473 510 purple_blist_remove_buddy(pb); 474 511 } 475 512 476 purple_gg_buddylist_export( ((PurpleAccount *) ic->proto_data)->gc);513 purple_gg_buddylist_export(pd->account->gc); 477 514 } 478 515 479 516 static void purple_add_permit(struct im_connection *ic, char *who) 480 517 { 481 PurpleAccount *pa= ic->proto_data;482 483 purple_privacy_permit_add(p a, who, FALSE);518 struct purple_data *pd = ic->proto_data; 519 520 purple_privacy_permit_add(pd->account, who, FALSE); 484 521 } 485 522 486 523 static void purple_add_deny(struct im_connection *ic, char *who) 487 524 { 488 PurpleAccount *pa= ic->proto_data;489 490 purple_privacy_deny_add(p a, who, FALSE);525 struct purple_data *pd = ic->proto_data; 526 527 purple_privacy_deny_add(pd->account, who, FALSE); 491 528 } 492 529 493 530 static void purple_rem_permit(struct im_connection *ic, char *who) 494 531 { 495 PurpleAccount *pa= ic->proto_data;496 497 purple_privacy_permit_remove(p a, who, FALSE);532 struct purple_data *pd = ic->proto_data; 533 534 purple_privacy_permit_remove(pd->account, who, FALSE); 498 535 } 499 536 500 537 static void purple_rem_deny(struct im_connection *ic, char *who) 501 538 { 502 PurpleAccount *pa= ic->proto_data;503 504 purple_privacy_deny_remove(p a, who, FALSE);539 struct purple_data *pd = ic->proto_data; 540 541 purple_privacy_deny_remove(pd->account, who, FALSE); 505 542 } 506 543 507 544 static void purple_get_info(struct im_connection *ic, char *who) 508 545 { 509 serv_get_info(purple_account_get_connection(ic->proto_data), who); 546 struct purple_data *pd = ic->proto_data; 547 548 serv_get_info(purple_account_get_connection(pd->account), who); 510 549 } 511 550 … … 517 556 { 518 557 PurpleTypingState state = PURPLE_NOT_TYPING; 519 PurpleAccount *pa= ic->proto_data;558 struct purple_data *pd = ic->proto_data; 520 559 521 560 if (flags & OPT_TYPING) { … … 525 564 } 526 565 527 serv_send_typing(purple_account_get_connection(p a), who, state);566 serv_send_typing(purple_account_get_connection(pd->account), who, state); 528 567 529 568 return 1; … … 559 598 /* There went my nice afternoon. :-( */ 560 599 561 PurpleAccount *pa= ic->proto_data;562 PurplePlugin *prpl = purple_plugins_find_with_id(p a->protocol_id);600 struct purple_data *pd = ic->proto_data; 601 PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id); 563 602 PurplePluginProtocolInfo *pi = prpl->info->extra_info; 564 PurpleBuddy *pb = purple_find_buddy( (PurpleAccount *) ic->proto_data, who);603 PurpleBuddy *pb = purple_find_buddy(pd->account, who); 565 604 PurpleMenuAction *mi; 566 605 GList *menu; … … 597 636 PurpleConversation *pc = gc->data; 598 637 PurpleConvChat *pcc = PURPLE_CONV_CHAT(pc); 599 600 serv_chat_invite(purple_account_get_connection(gc->ic->proto_data), 638 struct purple_data *pd = gc->ic->proto_data; 639 640 serv_chat_invite(purple_account_get_connection(pd->account), 601 641 purple_conv_chat_get_id(pcc), 602 642 message && *message ? message : "Please join my chat", … … 623 663 set_t **sets) 624 664 { 625 PurpleAccount *pa= ic->proto_data;626 PurplePlugin *prpl = purple_plugins_find_with_id(p a->protocol_id);665 struct purple_data *pd = ic->proto_data; 666 PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id); 627 667 PurplePluginProtocolInfo *pi = prpl->info->extra_info; 628 668 GHashTable *chat_hash; … … 631 671 632 672 if (!pi->chat_info || !pi->chat_info_defaults || 633 !(info = pi->chat_info(purple_account_get_connection(p a)))) {673 !(info = pi->chat_info(purple_account_get_connection(pd->account)))) { 634 674 imcb_error(ic, "Joining chatrooms not supported by this protocol"); 635 675 return NULL; 636 676 } 637 677 638 if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, room, pa))) { 678 if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 679 room, pd->account))) { 639 680 purple_conversation_destroy(conv); 640 681 } 641 682 642 chat_hash = pi->chat_info_defaults(purple_account_get_connection(pa), room); 683 chat_hash = pi->chat_info_defaults( 684 purple_account_get_connection(pd->account), room 685 ); 643 686 644 687 for (l = info; l; l = l->next) { … … 654 697 } 655 698 656 serv_join_chat(purple_account_get_connection(p a), chat_hash);699 serv_join_chat(purple_account_get_connection(pd->account), chat_hash); 657 700 658 701 return NULL; … … 981 1024 pqad->yes(pqad->user_data, pqad->yes_i); 982 1025 } 983 g_free(pqad);984 1026 } 985 1027 … … 991 1033 pqad->no(pqad->user_data, pqad->no_i); 992 1034 } 993 g_free(pqad); 1035 } 1036 1037 /* q->free() callback from query_del()*/ 1038 static void prplcb_request_action_free(void *data) 1039 { 1040 struct prplcb_request_action_data *pqad = data; 1041 1042 pqad->bee_data = NULL; 1043 purple_request_close(PURPLE_REQUEST_ACTION, pqad); 994 1044 } 995 1045 … … 1026 1076 q = g_strdup_printf("Request: %s\n\n%s\n\n%s", title, primary, secondary); 1027 1077 pqad->bee_data = query_add(local_bee->ui_data, purple_ic_by_pa(account), q, 1028 prplcb_request_action_yes, prplcb_request_action_no, g_free, pqad); 1078 prplcb_request_action_yes, prplcb_request_action_no, 1079 prplcb_request_action_free, pqad); 1029 1080 1030 1081 g_free(q); … … 1033 1084 } 1034 1085 1035 /* 1036 static void prplcb_request_test() 1037 { 1038 fprintf( stderr, "bla\n" ); 1039 } 1040 */ 1086 /* So it turns out some requests have no account context at all, because 1087 * libpurple hates us. This means that query_del_by_conn() won't remove those 1088 * on logout, and will segfault if the user replies. That's why this exists. 1089 */ 1090 static void prplcb_close_request(PurpleRequestType type, void *data) 1091 { 1092 struct prplcb_request_action_data *pqad; 1093 struct request_input_data *ri; 1094 struct purple_data *pd; 1095 1096 if (!data) { 1097 return; 1098 } 1099 1100 switch (type) { 1101 case PURPLE_REQUEST_ACTION: 1102 pqad = data; 1103 /* if this is null, it's because query_del was run already */ 1104 if (pqad->bee_data) { 1105 query_del(local_bee->ui_data, pqad->bee_data); 1106 } 1107 g_free(pqad); 1108 break; 1109 case PURPLE_REQUEST_INPUT: 1110 ri = data; 1111 pd = ri->ic->proto_data; 1112 imcb_remove_buddy(ri->ic, ri->buddy, NULL); 1113 g_free(ri->buddy); 1114 g_hash_table_remove(pd->input_requests, GUINT_TO_POINTER(ri->id)); 1115 break; 1116 default: 1117 g_free(data); 1118 break; 1119 } 1120 1121 } 1122 1123 void* prplcb_request_input(const char *title, const char *primary, 1124 const char *secondary, const char *default_value, gboolean multiline, 1125 gboolean masked, gchar *hint, const char *ok_text, GCallback ok_cb, 1126 const char *cancel_text, GCallback cancel_cb, PurpleAccount *account, 1127 const char *who, PurpleConversation *conv, void *user_data) 1128 { 1129 struct im_connection *ic = purple_ic_by_pa(account); 1130 struct purple_data *pd = ic->proto_data; 1131 struct request_input_data *ri = g_new0(struct request_input_data, 1); 1132 guint id = pd->next_request_id++; 1133 1134 ri->id = id; 1135 ri->ic = ic; 1136 ri->buddy = g_strdup_printf("%s_%u", PURPLE_REQUEST_HANDLE, id); 1137 ri->data_callback = (ri_callback_t) ok_cb; 1138 ri->user_data = user_data; 1139 g_hash_table_insert(pd->input_requests, GUINT_TO_POINTER(id), ri); 1140 1141 imcb_add_buddy(ic, ri->buddy, NULL); 1142 imcb_buddy_msg(ic, ri->buddy, secondary, 0, 0); 1143 1144 return ri; 1145 } 1146 1147 void purple_request_input_callback(guint id, struct im_connection *ic, 1148 const char *message, const char *who) 1149 { 1150 struct purple_data *pd = ic->proto_data; 1151 struct request_input_data *ri; 1152 1153 if (!(ri = g_hash_table_lookup(pd->input_requests, GUINT_TO_POINTER(id)))) { 1154 return; 1155 } 1156 1157 ri->data_callback(ri->user_data, message); 1158 1159 purple_request_close(PURPLE_REQUEST_INPUT, ri); 1160 } 1161 1041 1162 1042 1163 static PurpleRequestUiOps bee_request_uiops = 1043 1164 { 1044 NULL,1165 prplcb_request_input, 1045 1166 NULL, 1046 1167 prplcb_request_action, 1047 1168 NULL, 1048 1169 NULL, 1049 NULL,1170 prplcb_close_request, 1050 1171 NULL, 1051 1172 }; -
protocols/skype/Makefile
r531eabd rb1dc403 6 6 DATE := $(shell date +%Y-%m-%d) 7 7 INSTALL = install 8 ASCIIDOC = yes9 8 10 ifeq ($(ASCIIDOC),yes) 9 10 ifdef ASCIIDOC 11 11 MANPAGES = skyped.1 12 12 else … … 29 29 30 30 install-doc: doc 31 if eq ($(ASCIIDOC),yes)31 ifdef ASCIIDOC 32 32 $(INSTALL) -d $(DESTDIR)$(MANDIR)/man1 33 33 $(INSTALL) -m644 $(MANPAGES) $(DESTDIR)$(MANDIR)/man1 -
protocols/twitter/twitter.c
r531eabd rb1dc403 852 852 } 853 853 854 /* Parses a decimal or hex tweet ID, returns TRUE on success */ 855 static gboolean twitter_parse_id(char *string, int base, guint64 *id) 856 { 857 guint64 parsed; 858 char *endptr; 859 860 errno = 0; 861 parsed = g_ascii_strtoull(string, &endptr, base); 862 if (errno || endptr == string || *endptr != '\0') { 863 return FALSE; 864 } 865 *id = parsed; 866 return TRUE; 867 } 868 869 bee_user_t twitter_log_local_user; 870 854 871 /** Convert the given bitlbee tweet ID, bitlbee username, or twitter tweet ID 855 872 * into a twitter tweet ID. … … 879 896 arg++; 880 897 } 881 if (sscanf(arg, "%" G_GINT64_MODIFIER "x", &id) == 1 && 882 id < TWITTER_LOG_LENGTH) { 898 if (twitter_parse_id(arg, 16, &id) && id < TWITTER_LOG_LENGTH) { 883 899 bu = td->log[id].bu; 884 900 id = td->log[id].id; 885 /* Beware of dangling pointers! */ 886 if (!g_slist_find(ic->bee->users, bu)) { 887 bu = NULL; 888 } 889 } else if (sscanf(arg, "%" G_GINT64_MODIFIER "d", &id) == 1) { 901 } else if (twitter_parse_id(arg, 10, &id)) { 890 902 /* Allow normal tweet IDs as well; not a very useful 891 903 feature but it's always been there. Just ignore … … 897 909 } 898 910 if (bu_) { 911 if (bu == &twitter_log_local_user) { 912 /* HACK alert. There's no bee_user object for the local 913 * user so just fake one for the few cmds that need it. */ 914 twitter_log_local_user.handle = td->user; 915 } else { 916 /* Beware of dangling pointers! */ 917 if (!g_slist_find(ic->bee->users, bu)) { 918 bu = NULL; 919 } 920 } 899 921 *bu_ = bu; 900 922 } … … 989 1011 in_reply_to = id; 990 1012 allow_post = TRUE; 1013 } else if (g_strcasecmp(cmd[0], "url") == 0) { 1014 id = twitter_message_id_from_command_arg(ic, cmd[1], &bu); 1015 if (!id) { 1016 twitter_log(ic, "Tweet `%s' does not exist", cmd[1]); 1017 } else { 1018 /* More common link is twitter.com/$UID/status/$ID (and that's 1019 * what this will 302 to) but can't generate that since for RTs, 1020 * bu here points at the retweeter while id contains the id of 1021 * the original message. */ 1022 twitter_log(ic, "https://twitter.com/statuses/%lld", id); 1023 } 1024 goto eof; 1025 991 1026 } else if (g_strcasecmp(cmd[0], "post") == 0) { 992 1027 message += 5; -
protocols/twitter/twitter.h
r531eabd rb1dc403 101 101 struct twitter_log_data { 102 102 guint64 id; 103 struct bee_user *bu; /* DANGER: can be a dead pointer. Check it first. */ 103 /* DANGER: bu can be a dead pointer. Check it first. 104 * twitter_message_id_from_command_arg() will do this. */ 105 struct bee_user *bu; 104 106 }; 105 107 … … 110 112 */ 111 113 extern GSList *twitter_connections; 114 115 /** 116 * Evil hack: Fake bee_user which will always point at the local user. 117 * Sometimes used as a return value by twitter_message_id_from_command_arg. 118 * NOT thread safe but don't you dare to even think of ever making BitlBee 119 * threaded. :-) 120 */ 121 extern bee_user_t twitter_log_local_user; 112 122 113 123 void twitter_login_finish(struct im_connection *ic); -
protocols/twitter/twitter_lib.c
r531eabd rb1dc403 460 460 #endif 461 461 462 static char* expand_entities(char* text, const json_value *entities);462 static void expand_entities(char **text, const json_value *node); 463 463 464 464 /** … … 473 473 { 474 474 struct twitter_xml_status *txs; 475 const json_value *rt = NULL , *entities = NULL;475 const json_value *rt = NULL; 476 476 477 477 if (node->type != json_object) { … … 501 501 } else if (strcmp("in_reply_to_status_id", k) == 0 && v->type == json_integer) { 502 502 txs->reply_to = v->u.integer; 503 } else if (strcmp("entities", k) == 0 && v->type == json_object) {504 entities = v;505 503 } 506 504 } … … 516 514 txs_free(rtxs); 517 515 } 518 } else if (entities){519 txs->text = expand_entities(txs->text, entities);516 } else { 517 expand_entities(&txs->text, node); 520 518 } 521 519 … … 534 532 { 535 533 struct twitter_xml_status *txs; 536 const json_value *entities = NULL;537 534 538 535 if (node->type != json_object) { … … 561 558 } 562 559 563 if (entities) { 564 txs->text = expand_entities(txs->text, entities); 565 } 560 expand_entities(&txs->text, node); 566 561 567 562 if (txs->text && txs->user && txs->id) { … … 573 568 } 574 569 575 static char* expand_entities(char* text, const json_value *entities) 576 { 570 static void expand_entities(char **text, const json_value *node) 571 { 572 json_value *entities, *quoted; 573 char *quote_url = NULL, *quote_text = NULL; 574 575 if (!((entities = json_o_get(node, "entities")) && entities->type == json_object)) 576 return; 577 if ((quoted = json_o_get(node, "quoted_status")) && quoted->type == json_object) { 578 /* New "retweets with comments" feature. Note that this info 579 * seems to be included in the streaming API only! Grab the 580 * full message and try to insert it when we run into the 581 * Tweet entity. */ 582 struct twitter_xml_status *txs = twitter_xt_get_status(quoted); 583 quote_text = g_strdup_printf("@%s: %s", txs->user->screen_name, txs->text); 584 quote_url = g_strdup_printf("%s/status/%" G_GUINT64_FORMAT, txs->user->screen_name, txs->id); 585 txs_free(txs); 586 } else { 587 quoted = NULL; 588 } 589 577 590 JSON_O_FOREACH(entities, k, v) { 578 591 int i; … … 586 599 587 600 for (i = 0; i < v->u.array.length; i++) { 601 const char *format = "%s%s <%s>%s"; 602 588 603 if (v->u.array.values[i]->type != json_object) { 589 604 continue; … … 592 607 const char *kort = json_o_str(v->u.array.values[i], "url"); 593 608 const char *disp = json_o_str(v->u.array.values[i], "display_url"); 609 const char *full = json_o_str(v->u.array.values[i], "expanded_url"); 594 610 char *pos, *new; 595 611 596 if (!kort || !disp || !(pos = strstr( text, kort))) {612 if (!kort || !disp || !(pos = strstr(*text, kort))) { 597 613 continue; 598 614 } 615 if (quote_url && strstr(full, quote_url)) { 616 format = "%s<%s> [%s]%s"; 617 disp = quote_text; 618 } 599 619 600 620 *pos = '\0'; 601 new = g_strdup_printf( "%s%s <%s>%s",text, kort,621 new = g_strdup_printf(format, *text, kort, 602 622 disp, pos + strlen(kort)); 603 623 604 g_free( text);605 text = new;606 } 607 } 608 609 return text;624 g_free(*text); 625 *text = new; 626 } 627 } 628 g_free(quote_text); 629 g_free(quote_url); 610 630 } 611 631 … … 681 701 if (g_strcasecmp(txs->user->screen_name, td->user) == 0) { 682 702 td->log[td->log_id].id = txs->rt_id; 703 /* More useful than NULL. */ 704 td->log[td->log_id].bu = &twitter_log_local_user; 683 705 } 684 706 … … 832 854 833 855 last_id_str = g_strdup_printf("%" G_GUINT64_FORMAT, td->timeline_id); 834 set_setstr(&ic->acc->set, " last_tweet", last_id_str);856 set_setstr(&ic->acc->set, "_last_tweet", last_id_str); 835 857 g_free(last_id_str); 836 858 } … … 862 884 863 885 imcb_error(ic, "Stream closed (%s)", req->status_string); 886 if (req->status_code == 401) { 887 imcb_error(ic, "Check your system clock."); 888 } 864 889 imc_logout(ic, TRUE); 865 890 return; -
protocols/yahoo/yahoo.c
r531eabd rb1dc403 733 733 inp = l->data; 734 734 if (inp->h == tag) { 735 byahoo_inputs = g_slist_remove(byahoo_inputs, inp); 735 736 g_free(inp->d); 736 737 g_free(inp); 737 byahoo_inputs = g_slist_remove(byahoo_inputs, inp);738 738 break; 739 739 } -
storage_xml.c
r531eabd rb1dc403 103 103 if (protocol) { 104 104 prpl = find_protocol(protocol); 105 if (!prpl) { 106 irc_rootmsg(xd->irc, "Error loading user config: Protocol not found: `%s'", protocol); 107 return XT_ABORT; 108 } 105 109 local = protocol_account_islocal(protocol); 106 110 } … … 124 128 } 125 129 } else { 130 g_free(pass_cr); 131 g_free(password); 126 132 return XT_ABORT; 127 133 } … … 197 203 fn = g_strconcat(global.conf->configdir, xd->given_nick, ".xml", NULL); 198 204 if ((fd = open(fn, O_RDONLY)) < 0) { 199 ret = STORAGE_NO_SUCH_USER; 205 if (errno == ENOENT) { 206 ret = STORAGE_NO_SUCH_USER; 207 } else { 208 irc_rootmsg(irc, "Error loading user config: %s", g_strerror(errno)); 209 } 200 210 goto error; 201 211 } … … 259 269 260 270 261 static gboolean xml_generate_nick(gpointer key, gpointer value, gpointer data);262 271 static void xml_generate_settings(struct xt_node *cur, set_t **head); 263 272 … … 292 301 293 302 for (acc = irc->b->accounts; acc; acc = acc->next) { 303 GHashTableIter iter; 304 gpointer key, value; 294 305 unsigned char *pass_cr; 295 306 char *pass_b64; … … 312 323 g_free(pass_b64); 313 324 314 /* This probably looks pretty strange. g_hash_table_foreach 315 is quite a PITA already (but it can't get much better in 316 C without using #define, I'm afraid), and it 317 doesn't seem to be possible to abort the foreach on write 318 errors, so instead let's use the _find function and 319 return TRUE on write errors. Which means, if we found 320 something, there was an error. :-) */ 321 g_hash_table_find(acc->nicks, xml_generate_nick, cur); 325 g_hash_table_iter_init(&iter, acc->nicks); 326 while (g_hash_table_iter_next(&iter, &key, &value)) { 327 struct xt_node *node = xt_new_node("buddy", NULL, NULL); 328 xt_add_attr(node, "handle", key); 329 xt_add_attr(node, "nick", value); 330 xt_add_child(cur, node); 331 } 322 332 323 333 xml_generate_settings(cur, &acc->set); … … 343 353 344 354 return root; 345 }346 347 static gboolean xml_generate_nick(gpointer key, gpointer value, gpointer data)348 {349 struct xt_node *node = xt_new_node("buddy", NULL, NULL);350 351 xt_add_attr(node, "handle", key);352 xt_add_attr(node, "nick", value);353 xt_add_child((struct xt_node *) data, node);354 355 return FALSE;356 355 } 357 356 … … 388 387 strcat(path, ".XXXXXX"); 389 388 if ((fd = mkstemp(path)) < 0) { 390 irc_rootmsg(irc, "Error while opening configuration file."); 391 return STORAGE_OTHER_ERROR; 389 goto error; 392 390 } 393 391 … … 411 409 412 410 error: 413 irc_rootmsg(irc, "Write error . Disk full?");411 irc_rootmsg(irc, "Write error: %s", g_strerror(errno)); 414 412 ret = STORAGE_OTHER_ERROR; 415 413
Note: See TracChangeset
for help on using the changeset viewer.