Changes in / [b1dc403:531eabd]
- Files:
-
- 3 added
- 3 deleted
- 49 edited
Legend:
- Unmodified
- Added
- Removed
-
.travis.yml
rb1dc403 r531eabd 1 1 language: c 2 3 script: 4 - ./configure 5 - make check 6 - dpkg-buildpackage -uc -us 7 2 script: ./configure && make check && dpkg-buildpackage -uc -us 8 3 before_install: 9 4 - sudo apt-get update -qq … … 12 7 - sudo dpkg -i *.deb 13 8 14 env:15 global:16 # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created17 # via the "travis encrypt" command using the project repo's public key18 - 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.ar26 build_command_prepend: ./configure --otr=1 --debug=127 build_command: make28 branch_pattern: coverity_scan29 30 notifications:31 email: false -
Makefile
rb1dc403 r531eabd 25 25 26 26 doc: 27 ifdef DOC28 27 $(MAKE) -C doc 29 endif30 28 31 29 uninstall: uninstall-bin uninstall-doc … … 75 73 76 74 install-doc: 77 ifdef DOC78 75 $(MAKE) -C doc install 79 endif80 76 ifdef SKYPE_PI 81 77 $(MAKE) -C protocols/skype install-doc … … 83 79 84 80 uninstall-doc: 85 ifdef DOC86 81 $(MAKE) -C doc uninstall 87 endif88 82 ifdef SKYPE_PI 89 83 $(MAKE) -C protocols/skype uninstall-doc … … 159 153 x=$$(basename $$(pwd)); \ 160 154 cd ..; \ 161 tar czf $$x.tar.gz --exclude =debian --exclude=.git* --exclude=.depend$$x155 tar czf $$x.tar.gz --exclude-from=.gitignore $$x 162 156 163 157 $(subdirs): -
bitlbee.h
rb1dc403 r531eabd 36 36 37 37 #define PACKAGE "BitlBee" 38 #define BITLBEE_VERSION "3. 4"38 #define BITLBEE_VERSION "3.2.2" 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, 4, 0)41 #define BITLBEE_VERSION_CODE BITLBEE_VER(3, 2, 2) 42 42 43 43 #define MAX_STRING 511 -
configure
rb1dc403 r531eabd 38 38 purple=0 39 39 40 doc=141 40 debug=0 42 41 strip=1 … … 57 56 GLIB_MIN_VERSION=2.16 58 57 58 echo BitlBee configure 59 59 60 # Cygwin and Darwin don't support PIC/PIE 60 61 case "$arch" in 61 62 63 64 62 CYGWIN* ) 63 pie=0;; 64 Darwin ) 65 pie=0;; 65 66 esac 66 67 get_version() {68 REAL_BITLBEE_VERSION=$(grep '^#define BITLBEE_VERSION ' $srcdir/bitlbee.h | sed 's/.*\"\(.*\)\".*/\1/')69 BITLBEE_VERSION=$REAL_BITLBEE_VERSION70 71 if [ -d $srcdir/.git ] && type git > /dev/null 2> /dev/null; then72 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 replace81 fi82 }83 84 if [ "$1" = "--dump-version" ]; then85 srcdir=$(cd $(dirname $0);pwd)86 get_version87 echo $BITLBEE_VERSION88 exit89 fi90 91 echo BitlBee configure92 67 93 68 while [ -n "$1" ]; do … … 121 96 --rpc=0/1 Disable/enable RPC interface $rpc 122 97 123 --doc=0/1 Disable/enable help.txt generation $doc124 98 --debug=0/1 Disable/enable debugging $debug 125 99 --strip=0/1 Disable/enable binary stripping $strip … … 476 450 ret=1 477 451 echo "$RESOLV_NS_TESTCODE" | $CC -o $TMPFILE -x c - $LIBRESOLV >/dev/null 2>/dev/null 478 479 480 452 if [ "$?" = "0" ]; then 453 ret=0 454 fi 481 455 482 456 rm -f $TMPFILE … … 491 465 if [ -f $i/libresolv.a ]; then 492 466 echo "$RESOLV_NS_TESTCODE" | $CC -o $TMPFILE -x c - -Wl,$i/libresolv.a >/dev/null 2>/dev/null 493 494 495 467 if [ "$?" = "0" ]; then 468 ret=0 469 fi 496 470 fi 497 471 done … … 503 477 detect_nameser_has_ns_types() 504 478 { 505 506 507 508 509 510 511 512 513 514 515 479 TMPFILE=$(mktemp /tmp/bitlbee-configure.XXXXXX) 480 ret=1 481 # since we aren't actually linking with ns_* routines 482 # we can just compile the test code 483 echo "$RESOLV_NS_TYPES_TESTCODE" | $CC -o $TMPFILE -x c - >/dev/null 2>/dev/null 484 if [ "$?" = "0" ]; then 485 ret=0 486 fi 487 488 rm -f $TMPFILE 489 return $ret 516 490 } 517 491 … … 574 548 if detect_resolv_dynamic || detect_resolv_static; then 575 549 echo '#define HAVE_RESOLV_A' >> config.h 576 577 578 579 else 580 550 if detect_resolv_ns_dynamic || detect_resolv_ns_static; then 551 echo '#define HAVE_RESOLV_A_WITH_NS' >> config.h 552 fi 553 else 554 echo 'Insufficient resolv routines. Jabber server must be set explicitly' 581 555 fi 582 556 … … 675 649 fi 676 650 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.' 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" 685 663 else 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 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 703 678 echo 'Spoofing version number: '$BITLBEE_VERSION 704 679 echo '#undef BITLBEE_VERSION' >> config.h 705 680 echo '#define BITLBEE_VERSION "'$BITLBEE_VERSION'"' >> config.h 706 681 echo 682 else 683 # for pkg-config 684 BITLBEE_VERSION=$REAL_BITLBEE_VERSION 707 685 fi 708 686 -
doc/CHANGES
rb1dc403 r531eabd 1 1 This ChangeLog mostly lists changes relevant to users. A full log can be 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 2 found in the bzr commit logs, for example you can try: 3 4 http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on 48 5 49 6 Version 3.2.2: -
doc/user-guide/commands.xml
rb1dc403 r531eabd 121 121 <description> 122 122 <para> 123 This command deletes an account from your account list. You should signoff the account before deleting it.123 This commands 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>856 855 </variablelist> 857 856 -
doc/user-guide/misc.xml
rb1dc403 r531eabd 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 435 411 </chapter> -
help.c
rb1dc403 r531eabd 30 30 #undef write 31 31 32 #define BUFSIZE 204832 #define BUFSIZE 1100 33 33 34 34 help_t *help_init(help_t **help, const char *helpfile) -
ipc.c
rb1dc403 r531eabd 776 776 } 777 777 778 child_list = g_slist_remove(child_list, c);779 780 778 g_free(c->host); 781 779 g_free(c->nick); … … 783 781 g_free(c->password); 784 782 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
rb1dc403 r531eabd 764 764 irc_rootmsg(irc, 765 765 "Welcome to the BitlBee gateway!\n\n" 766 "Running %s %s\n\n"767 766 "If you've never used BitlBee before, please do read the help " 768 767 "information using the \x02help\x02 command. Lots of FAQs are " 769 768 "answered there.\n" 770 769 "If you already have an account on this server, just use the " 771 "\x02identify\x02 command to identify yourself.", 772 PACKAGE, BITLBEE_VERSION); 770 "\x02identify\x02 command to identify yourself."); 773 771 774 772 /* This is for bug #209 (use PASS to identify to NickServ). */ -
irc.h
rb1dc403 r531eabd 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);303 301 void irc_channel_update_ops(irc_channel_t *ic, char *value); 304 302 char *set_eval_irc_channel_ops(struct set *set, char *value); -
irc_channel.c
rb1dc403 r531eabd 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 looks578 like it's not in use yet. Most likely the IRC client579 rejoined the channel after a reconnect. Remove it so580 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 638 558 static gint irc_channel_user_cmp(gconstpointer a_, gconstpointer b_) 639 559 { -
irc_im.c
rb1dc403 r531eabd 235 235 } else { 236 236 /* Modules can swallow messages. */ 237 goto cleanup;237 return TRUE; 238 238 } 239 239 } … … 250 250 wrapped = word_wrap(msg, 425); 251 251 irc_send_msg(iu, "PRIVMSG", dst, wrapped, prefix); 252 252 253 g_free(wrapped); 253 254 cleanup:255 254 g_free(prefix); 256 255 g_free(msg); … … 292 291 293 292 irc_send_msg((irc_user_t *) bu->ui_data, "NOTICE", irc->user->nick, msg->str, NULL); 294 295 g_string_free(msg, TRUE);296 293 297 294 return TRUE; … … 696 693 static gboolean bee_irc_chat_name_hint(bee_t *bee, struct groupchat *c, const char *name) 697 694 { 698 return irc_channel_name_hint(c->ui_data, name); 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; 699 744 } 700 745 -
irc_send.c
rb1dc403 r531eabd 55 55 { 56 56 char motd[2048]; 57 s size_t len;57 size_t len; 58 58 int fd; 59 59 -
lib/misc.c
rb1dc403 r531eabd 719 719 } 720 720 721 /* Make sure we're still inside the string */ 722 if (i >= len) { 723 return(NULL); 724 } 725 721 726 /* Copy the found data */ 722 727 return(g_strndup(ret, text + i - ret)); -
lib/oauth.c
rb1dc403 r531eabd 98 98 GSList *l, *n; 99 99 100 if ( !params) {100 if (params == NULL) { 101 101 return; 102 102 } … … 104 104 for (l = *params; l; l = n) { 105 105 n = l->next; 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);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); 111 111 } 112 112 } -
lib/proxy.c
rb1dc403 r531eabd 63 63 static int proxy_connect_none(const char *host, unsigned short port_, struct PHB *phb); 64 64 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) 65 static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition cond) 75 66 { 76 67 struct PHB *phb = data; … … 89 80 dup2(new_fd, source); 90 81 closesocket(new_fd); 91 phb->inpa = b_input_add(source, B_EV_IO_WRITE, proxy_connected, phb);82 phb->inpa = b_input_add(source, B_EV_IO_WRITE, gaim_io_connected, phb); 92 83 return FALSE; 93 84 } 94 85 } 86 freeaddrinfo(phb->gai); 95 87 closesocket(source); 96 source = -1; 97 /* socket is dead, but continue to clean up */ 98 } else { 99 sock_make_blocking(source); 100 } 101 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 } 102 98 freeaddrinfo(phb->gai); 99 sock_make_blocking(source); 103 100 b_event_remove(phb->inpa); 104 101 phb->inpa = 0; … … 163 160 continue; 164 161 } else { 165 phb->inpa = b_input_add(fd, B_EV_IO_WRITE, proxy_connected, phb);162 phb->inpa = b_input_add(fd, B_EV_IO_WRITE, gaim_io_connected, phb); 166 163 phb->fd = fd; 167 164 … … 209 206 } 210 207 211 return phb_close(phb); 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; 212 214 } 213 215 … … 224 226 len = sizeof(error); 225 227 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { 226 return phb_close(phb); 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; 227 233 } 228 234 sock_make_blocking(source); … … 231 237 phb->host, phb->port); 232 238 if (send(source, cmd, strlen(cmd), 0) < 0) { 233 return phb_close(phb); 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; 234 244 } 235 245 … … 242 252 g_free(t2); 243 253 if (send(source, cmd, strlen(cmd), 0) < 0) { 244 return phb_close(phb); 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; 245 259 } 246 260 } … … 248 262 g_snprintf(cmd, sizeof(cmd), "\r\n"); 249 263 if (send(source, cmd, strlen(cmd), 0) < 0) { 250 return phb_close(phb); 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; 251 269 } 252 270 … … 284 302 } 285 303 286 return phb_close(phb); 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; 287 310 } 288 311 … … 300 323 len = sizeof(error); 301 324 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { 302 return phb_close(phb); 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; 303 330 } 304 331 sock_make_blocking(source); … … 306 333 /* XXX does socks4 not support host name lookups by the proxy? */ 307 334 if (!(hp = gethostbyname(phb->host))) { 308 return phb_close(phb); 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; 309 340 } 310 341 … … 319 350 packet[8] = 0; 320 351 if (write(source, packet, 9) != 9) { 321 return phb_close(phb); 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; 322 357 } 323 358 … … 348 383 349 384 if (read(source, buf, 10) < 10) { 350 return phb_close(phb); 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; 351 390 } 352 391 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { 353 return phb_close(phb); 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; 354 397 } 355 398 … … 377 420 378 421 if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { 379 phb_close(phb); 422 close(source); 423 phb->func(phb->data, -1, B_EV_IO_READ); 424 g_free(phb->host); 425 g_free(phb); 380 426 return; 381 427 } … … 392 438 393 439 if (read(source, buf, 2) < 2) { 394 return phb_close(phb); 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; 395 445 } 396 446 397 447 if ((buf[0] != 0x01) || (buf[1] != 0x00)) { 398 return phb_close(phb); 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; 399 453 } 400 454 … … 412 466 413 467 if (read(source, buf, 2) < 2) { 414 return phb_close(phb); 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; 415 473 } 416 474 417 475 if ((buf[0] != 0x05) || (buf[1] == 0xff)) { 418 return phb_close(phb); 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; 419 481 } 420 482 … … 427 489 memcpy(buf + 2 + i + 1, proxypass, j); 428 490 if (write(source, buf, 3 + i + j) < 3 + i + j) { 429 return phb_close(phb); 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; 430 496 } 431 497 … … 451 517 len = sizeof(error); 452 518 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { 453 return phb_close(phb); 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; 454 524 } 455 525 sock_make_blocking(source); … … 469 539 470 540 if (write(source, buf, i) < i) { 471 return phb_close(phb); 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; 472 546 } 473 547 -
lib/ssl_gnutls.c
rb1dc403 r531eabd 124 124 125 125 if (conn->fd < 0) { 126 g_free(conn->hostname);127 126 g_free(conn); 128 127 return NULL; … … 315 314 if (source == -1) { 316 315 conn->func(conn->data, 0, NULL, cond); 317 g_free(conn->hostname);318 316 g_free(conn); 319 317 return FALSE; … … 357 355 conn->func(conn->data, 0, NULL, cond); 358 356 359 ssl_disconnect(conn); 357 gnutls_deinit(conn->session); 358 closesocket(conn->fd); 359 360 g_free(conn); 360 361 } 361 362 } else { … … 363 364 conn->func(conn->data, stver, NULL, cond); 364 365 365 ssl_disconnect(conn); 366 gnutls_deinit(conn->session); 367 closesocket(conn->fd); 368 369 g_free(conn); 366 370 } else { 367 371 /* For now we can't handle non-blocking perfectly everywhere... */ -
nick.c
rb1dc403 r531eabd 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 three225 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 232 216 void nick_dedupe(bee_user_t *bu, char nick[MAX_NICK_LENGTH + 1]) 233 217 { … … 240 224 while (!nick_ok(irc, nick) || 241 225 ((iu = irc_user_by_name(irc, nick)) && iu->bu != bu)) { 242 243 underscore_dedupe(nick); 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 } 244 237 245 238 if (inf_protection-- == 0) { -
nick.h
rb1dc403 r531eabd 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]);31 30 void nick_dedupe(bee_user_t * bu, char nick[MAX_NICK_LENGTH + 1]); 32 31 int nick_saved(bee_user_t *bu); -
otr.c
rb1dc403 r531eabd 287 287 void otr_irc_free(irc_t *irc) 288 288 { 289 set_t *s;290 289 otr_t *otr = irc->otr; 291 290 … … 293 292 b_event_remove(otr->timer); 294 293 otrl_userstate_free(otr->us); 295 296 s = set_find(&irc->b->set, "otr_policy");297 g_slist_free(s->eval_data);298 299 294 if (otr->keygen) { 300 295 kill(otr->keygen, SIGTERM); … … 439 434 ic->acc->user, ic->acc->prpl->name, iu->bu->handle, msg, &newmsg, 440 435 &tlvs, NULL, NULL, NULL); 441 442 if (tlvs) {443 otrl_tlv_free(tlvs);444 }445 436 446 437 if (ignore_msg) { … … 481 472 /* libotr wants us to replace our message */ 482 473 /* NB: caller will free old msg */ 483 msg = st ? NULL :g_strdup(otrmsg);474 msg = g_strdup(otrmsg); 484 475 otrl_message_free(otrmsg); 485 476 } … … 1334 1325 1335 1326 log_message(LOGLVL_INFO, "otr: %s", msg); 1336 1337 g_free(msg);1338 1327 } 1339 1328 … … 2086 2075 } 2087 2076 } 2077 2078 /* vim: set noet ts=4 sw=4: */ -
protocols/bee.h
rb1dc403 r531eabd 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 onst char *msg, guint32 flags,156 G_MODULE_EXPORT void imcb_buddy_msg(struct im_connection *ic, const char *handle, char *msg, guint32 flags, 157 157 time_t sent_at); 158 158 -
protocols/bee_user.c
rb1dc403 r531eabd 68 68 } 69 69 70 bee->users = g_slist_remove(bee->users, bu);71 72 70 g_free(bu->handle); 73 71 g_free(bu->fullname); … … 76 74 g_free(bu->status_msg); 77 75 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 onst char *msg, uint32_t flags, time_t sent_at)249 void imcb_buddy_msg(struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at) 250 250 { 251 251 bee_t *bee = ic->bee; -
protocols/jabber/Makefile
rb1dc403 r531eabd 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 hipchat.o15 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o s5bytestream.o sasl.o si.o 16 16 17 17 LFLAGS += -r -
protocols/jabber/conference.c
rb1dc403 r531eabd 359 359 360 360 if (subject && chat) { 361 s = (bud && bud->ext_jid)? strchr(bud->ext_jid, '/') : NULL;361 s = bud ? 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 = (bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL;421 s = strchr(bud->ext_jid, '/'); 422 422 if (s) { 423 423 *s = 0; -
protocols/jabber/iq.c
rb1dc403 r531eabd 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); 29 30 30 31 xt_status jabber_pkt_iq(struct xt_node *node, gpointer data) … … 373 374 static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 374 375 { 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");391 390 392 391 if (jid && sub) { … … 397 396 if (name) { 398 397 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);405 398 } 406 399 } else if (strcmp(sub, "remove") == 0) { … … 862 855 struct xt_node *node, struct xt_node *orig); 863 856 864 int jabber_iq_disco_server(struct im_connection *ic)857 static int jabber_iq_disco_server(struct im_connection *ic) 865 858 { 866 859 struct xt_node *node, *iq; -
protocols/jabber/jabber.c
rb1dc403 r531eabd 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 63 65 s = set_add(&acc->set, "display_name", NULL, NULL, acc); 64 66 … … 81 83 s = set_add(&acc->set, "server", NULL, set_eval_account, acc); 82 84 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 }89 85 90 86 s = set_add(&acc->set, "ssl", "false", set_eval_bool, acc); … … 125 121 126 122 jd->fd = jd->r_inpa = jd->w_inpa = -1; 127 128 if (strcmp(acc->prpl->name, "hipchat") == 0) {129 jd->flags |= JFLAG_HIPCHAT;130 }131 123 132 124 if (jd->server == NULL) { … … 664 656 { 665 657 struct prpl *ret = g_new0(struct prpl, 1); 666 struct prpl *hipchat = NULL;667 658 668 659 ret->name = "jabber"; … … 695 686 696 687 register_protocol(ret); 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 } 688 } -
protocols/jabber/jabber.h
rb1dc403 r531eabd 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 */51 50 52 51 JFLAG_SASL_FB = 0x10000, /* Trying Facebook authentication. */ … … 236 235 #define XMLNS_IBB "http://jabber.org/protocol/ibb" /* XEP-0047 */ 237 236 238 /* Hipchat protocol extensions*/239 #define XMLNS_HIPCHAT "http://hipchat.com"240 #define XMLNS_HIPCHAT_PROFILE "http://hipchat.com/protocol/profile"241 242 237 /* jabber.c */ 243 238 void jabber_connect(struct im_connection *ic); … … 254 249 xt_status jabber_iq_query_server(struct im_connection *ic, char *jid, char *xmlns); 255 250 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);257 251 258 252 /* si.c */ … … 347 341 void jabber_chat_invite(struct groupchat *c, char *who, char *message); 348 342 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 354 343 #endif -
protocols/jabber/jabber_util.c
rb1dc403 r531eabd 566 566 567 567 if ((s = strchr(jid, '=')) == NULL) { 568 g_free(jid);569 568 return NULL; 570 569 } -
protocols/jabber/s5bytestream.c
rb1dc403 r531eabd 23 23 24 24 #include "jabber.h" 25 #include "sha1.h" 25 26 #include "lib/ftutil.h" 26 27 #include <poll.h> … … 41 42 42 43 /* SHA1( SID + Initiator JID + Target JID) */ 43 char *pseudoad dr;44 char *pseudoadr; 44 45 45 46 gint connect_timeout; … … 129 130 } 130 131 131 g_free(bt->pseudoad dr);132 g_free(bt->pseudoadr); 132 133 133 134 while (bt->streamhosts) { … … 253 254 } 254 255 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 280 256 /* Bad luck */ 281 257 void jabber_bs_canceled(file_transfer_t *ft, char *reason) … … 284 260 285 261 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 value300 * 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;317 262 } 318 263 … … 325 270 struct jabber_data *jd = ic->proto_data; 326 271 struct jabber_transfer *tf = NULL; 272 GSList *tflist; 327 273 struct bs_transfer *bt; 328 274 GSList *shlist = NULL; 329 275 struct xt_node *shnode; 276 277 sha1_state_t sha; 278 char hash_hex[41]; 279 unsigned char hash[20]; 280 int i; 330 281 331 282 if (!(iq_id = xt_find_attr(node, "id")) || … … 352 303 (port_s = xt_find_attr(shnode, "port")) && 353 304 (sscanf(port_s, "%d", &port) == 1)) { 354 shlist = g_slist_append(shlist, jabber_streamhost_new(jid, host, port)); 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); 355 310 } 356 311 shnode = shnode->next; … … 362 317 } 363 318 364 if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) { 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) { 365 332 imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid); 366 333 return XT_HANDLED; … … 372 339 373 340 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 } 374 352 375 353 bt = g_new0(struct bs_transfer, 1); … … 378 356 bt->sh = shlist->data; 379 357 bt->phase = BS_PHASE_CONNECT; 380 bt->pseudoad dr = generate_pseudoaddr(sid, ini_jid, tgt_jid);358 bt->pseudoadr = g_strdup(hash_hex); 381 359 tf->streamhandle = bt; 382 360 tf->ft->free = jabber_bs_free_transfer; … … 473 451 .rsv = 0, 474 452 .atyp = 0x03, 475 .addrlen = strlen(bt->pseudoad dr),453 .addrlen = strlen(bt->pseudoadr), 476 454 .port = 0 477 455 }; … … 490 468 491 469 /* copy hash into connect message */ 492 memcpy(socks5_connect.address, bt->pseudoad dr, socks5_connect.addrlen);470 memcpy(socks5_connect.address, bt->pseudoadr, socks5_connect.addrlen); 493 471 494 472 ASSERTSOCKOP(send(fd, &socks5_connect, sizeof(struct socks5_message), 0), "Sending SOCKS5 Connect"); … … 580 558 if (shlist && shlist->next) { 581 559 bt->sh = shlist->next->data; 582 jabber_bs_remove_events(bt);583 560 return jabber_bs_recv_handshake(bt, -1, 0); 584 561 } … … 754 731 struct jabber_data *jd = ic->proto_data; 755 732 struct bs_transfer *bt; 733 GSList *tflist; 756 734 struct xt_node *c; 757 735 char *sid, *jid; … … 772 750 /* Let's see if we can find out what this bytestream should be for... */ 773 751 774 if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) { 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) { 775 761 imcb_log(ic, "WARNING: Received SOCKS5 bytestream reply to unknown request"); 776 762 return XT_HANDLED; … … 790 776 /* using a proxy, abort listen */ 791 777 792 jabber_bs_remove_events(bt); 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 } 793 792 794 793 GSList *shlist; … … 839 838 { 840 839 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 if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) { 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) { 849 857 imcb_log(ic, "WARNING: Received SOCKS5 bytestream activation for unknown stream"); 850 858 return XT_HANDLED; … … 875 883 *port++ = '\0'; 876 884 877 sh = jabber_streamhost_new(jid, host, 0); 878 strncpy(sh->port, port, sizeof(sh->port)); 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); 879 889 880 890 return sh; … … 900 910 if (strcmp(proxy, "<local>") == 0) { 901 911 if ((tf->fd = ft_listen(&tf->saddr, host, port, jd->fd, FALSE, &errmsg)) != -1) { 902 sh = jabber_streamhost_new(tf->ini_jid, host, 0); 903 strncpy(sh->port, port, sizeof(sh->port)); 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); 904 916 bt->streamhosts = g_slist_append(bt->streamhosts, sh); 905 917 … … 936 948 { 937 949 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 } 938 965 939 966 bt = g_new0(struct bs_transfer, 1); 940 967 bt->tf = tf; 941 968 bt->phase = BS_PHASE_CONNECT; 942 bt->pseudoad dr = generate_pseudoaddr(tf->sid, tf->ini_jid, tf->tgt_jid);969 bt->pseudoadr = g_strdup(hash_hex); 943 970 tf->streamhandle = bt; 944 971 tf->ft->free = jabber_bs_free_transfer; … … 947 974 jabber_si_set_proxies(bt); 948 975 949 return jabber_bs_send_request(tf, bt->streamhosts); 976 ret = jabber_bs_send_request(tf, bt->streamhosts); 977 978 return ret; 950 979 } 951 980 … … 1110 1139 socks5_connect.atyp); 1111 1140 } 1112 if (!(memcmp(socks5_connect.address, bt->pseudoad dr, 40) == 0)) {1141 if (!(memcmp(socks5_connect.address, bt->pseudoadr, 40) == 0)) { 1113 1142 return jabber_bs_abort(bt, "SOCKS5 Connect message contained wrong digest"); 1114 1143 } -
protocols/jabber/sasl.c
rb1dc403 r531eabd 42 42 "https://www.facebook.com/dialog/oauth", 43 43 "https://graph.facebook.com/oauth/access_token", 44 "http s://www.bitlbee.org/main.php/Facebook/oauth2.html",44 "http://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 , want_hipchat = FALSE;57 int want_oauth = 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);78 77 79 78 mechs = g_string_new(""); … … 112 111 113 112 reply = xt_new_node("auth", NULL, NULL); 114 if (!want_hipchat) { 115 xt_add_attr(reply, "xmlns", XMLNS_SASL); 116 } else { 117 xt_add_attr(reply, "xmlns", XMLNS_HIPCHAT); 118 } 113 xt_add_attr(reply, "xmlns", XMLNS_SASL); 119 114 120 115 if (sup_gtalk && want_oauth) { … … 148 143 } else if (sup_plain) { 149 144 int len; 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); 145 146 xt_add_attr(reply, "mechanism", "PLAIN"); 162 147 163 148 /* With SASL PLAIN in XMPP, the text should be b64(\0user\0pass) */ 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 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); 177 154 reply->text = base64_encode((unsigned char *) s, len); 178 155 reply->text_len = strlen(reply->text); … … 420 397 imcb_log(ic, "Authentication finished"); 421 398 jd->flags |= JFLAG_AUTHENTICATED | JFLAG_STREAM_RESTART; 422 423 if (jd->flags & JFLAG_HIPCHAT) {424 return hipchat_handle_success(ic, node);425 }426 399 } else if (strcmp(node->name, "failure") == 0) { 427 400 imcb_error(ic, "Authentication failure"); -
protocols/msn/Makefile
rb1dc403 r531eabd 13 13 14 14 # [SH] Program variables 15 objects = msn.o msn_util.o ns.o s oap.o tables.o gw.o15 objects = msn.o msn_util.o ns.o sb.o soap.o tables.o 16 16 17 17 LFLAGS += -r -
protocols/msn/msn.c
rb1dc403 r531eabd 30 30 int msn_chat_id; 31 31 GSList *msn_connections; 32 GSList *msn_switchboards; 32 33 33 34 static char *set_eval_display_name(set_t *set, char *value); … … 40 41 s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY; 41 42 42 s = set_add(&acc->set, "server", NULL, set_eval_account, acc);43 s = set_add(&acc->set, "server", MSN_NS_HOST, set_eval_account, acc); 43 44 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY; 44 45 … … 47 48 48 49 set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc); 50 set_add(&acc->set, "switchboard_keepalives", "false", set_eval_bool, acc); 49 51 50 52 acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE | … … 56 58 struct im_connection *ic = imcb_new(acc); 57 59 struct msn_data *md = g_new0(struct msn_data, 1); 58 char *server = set_getstr(&ic->acc->set, "server");59 60 60 61 ic->proto_data = md; 61 62 ic->flags |= OPT_PONGS | OPT_PONGED; 62 63 if (!server) {64 server = "geo.gateway.messenger.live.com";65 }66 63 67 64 if (strchr(acc->user, '@') == NULL) { … … 74 71 md->away_state = msn_away_state_list; 75 72 md->domaintree = g_tree_new(msn_domaintree_cmp); 76 md->fd = -1; 77 md->is_http = TRUE; 73 md->ns->fd = -1; 78 74 79 75 msn_connections = g_slist_prepend(msn_connections, ic); 80 76 81 77 imcb_log(ic, "Connecting"); 82 msn_ns_connect(ic, server, 78 msn_ns_connect(ic, md->ns, 79 set_getstr(&ic->acc->set, "server"), 83 80 set_getint(&ic->acc->set, "port")); 84 81 } … … 91 88 92 89 if (md) { 93 msn_ns_close(md); 94 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); 95 103 msn_soapq_flush(ic, FALSE); 96 104 … … 104 112 while (md->groups) { 105 113 struct msn_group *mg = md->groups->data; 106 md->groups = g_slist_remove(md->groups, mg);107 114 g_free(mg->id); 108 115 g_free(mg->name); 109 116 g_free(mg); 117 md->groups = g_slist_remove(md->groups, mg); 110 118 } 111 119 … … 119 127 while (md->grpq) { 120 128 struct msn_groupadd *ga = md->grpq->data; 121 md->grpq = g_slist_remove(md->grpq, ga);122 129 g_free(ga->group); 123 130 g_free(ga->who); 124 131 g_free(ga); 132 md->grpq = g_slist_remove(md->grpq, ga); 125 133 } 126 134 … … 144 152 { 145 153 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; 146 156 147 157 #ifdef DEBUG 148 158 if (strcmp(who, "raw") == 0) { 149 159 msn_ns_write(ic, -1, "%s\r\n", message); 150 return 0; 151 } 160 } else 152 161 #endif 153 154 msn_ns_sendmessage(ic, bu, message); 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 155 177 return(0); 156 178 } … … 174 196 static void msn_set_away(struct im_connection *ic, char *state, char *message) 175 197 { 198 char *uux; 176 199 struct msn_data *md = ic->proto_data; 177 char *nick, *psm, *idle, *statecode, *body, *buf;178 200 179 201 if (state == NULL) { … … 183 205 } 184 206 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); 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); 202 233 } 203 234 … … 225 256 static void msn_chat_msg(struct groupchat *c, char *message, int flags) 226 257 { 227 /* TODO: groupchats*/ 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! */ 228 265 } 229 266 230 267 static void msn_chat_invite(struct groupchat *c, char *who, char *message) 231 268 { 232 /* TODO: groupchats*/ 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 } 233 274 } 234 275 235 276 static void msn_chat_leave(struct groupchat *c) 236 277 { 237 /* TODO: groupchats*/ 278 struct msn_switchboard *sb = msn_sb_by_chat(c); 279 280 if (sb) { 281 msn_sb_write(sb, "OUT\r\n"); 282 } 238 283 } 239 284 240 285 static struct groupchat *msn_chat_with(struct im_connection *ic, char *who) 241 286 { 242 /* TODO: groupchats*/287 struct msn_switchboard *sb; 243 288 struct groupchat *c = imcb_chat_new(ic, who); 244 return c; 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 } 245 305 } 246 306 … … 262 322 static void msn_add_deny(struct im_connection *ic, char *who) 263 323 { 324 struct msn_switchboard *sb; 325 264 326 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 } 265 332 } 266 333 … … 395 462 ret->buddy_action = msn_buddy_action; 396 463 464 //ret->transfer_request = msn_ftp_transfer_request; 465 397 466 register_protocol(ret); 398 467 } -
protocols/msn/msn.h
rb1dc403 r531eabd 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" 34 35 35 36 #ifdef DEBUG_MSN … … 59 60 #define MSNP11_PROD_KEY "C1BX{V4W}Q3*10SM" 60 61 #define MSNP11_PROD_ID "PROD0120PW!CCV9@" 61 #define MSNP_VER "MSNP 21"62 #define MSNP_VER "MSNP18" 62 63 #define MSNP_BUILD "14.0.8117.416" 63 64 … … 67 68 #define MSN_CAP2 0x0000 68 69 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" \ 70 #define MSN_MESSAGE_HEADERS "MIME-Version: 1.0\r\n" \ 71 "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" \ 75 74 "\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" \81 "Content-Type: text/plain; charset=UTF-8\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>"104 75 105 76 #define MSN_TYPING_HEADERS "MIME-Version: 1.0\r\n" \ … … 113 84 "ID: 1\r\n" \ 114 85 "\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" 115 90 116 91 #define PROFILE_URL "http://members.msn.com/" … … 124 99 } msn_flags_t; 125 100 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 { 101 struct msn_handler_data { 149 102 int fd, inpa; 150 103 int rxlen; … … 154 107 char *cmd_text; 155 108 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 { 156 117 struct im_connection *ic; 157 118 119 struct msn_handler_data ns[1]; 158 120 msn_flags_t flags; 159 121 … … 164 126 165 127 GSList *msgq, *grpq, *soapq; 128 GSList *switchboards; 129 int sb_failures; 130 time_t first_sb_failure; 166 131 167 132 const struct msn_away_state *away_state; … … 174 139 GTree *domaintree; 175 140 int adl_todo; 176 177 gboolean is_http; 178 struct msn_gw *gw; 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; 179 161 }; 180 162 … … 223 205 #define STATUS_FATAL 1 224 206 #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). */ 225 209 226 210 extern int msn_chat_id; … … 234 218 before doing *anything* else. */ 235 219 extern GSList *msn_connections; 220 extern GSList *msn_switchboards; 236 221 237 222 /* ns.c */ 238 223 int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) G_GNUC_PRINTF(3, 4); 239 gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port);240 void msn_ns_close(struct msn_ data *handler);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); 241 226 void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error); 242 227 void msn_auth_got_contact_list(struct im_connection *ic); 243 228 int msn_ns_finish_login(struct im_connection *ic); 244 229 int msn_ns_sendmessage(struct im_connection *ic, struct bee_user *bu, const char *text); 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); 230 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq); 247 231 248 232 /* msn_util.c */ … … 251 235 int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group); 252 236 void msn_buddy_ask(bee_user_t *bu); 253 void msn_queue_feed(struct msn_data *h, char *bytes, int st); 254 int msn_handler(struct msn_data *h); 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); 255 240 char *msn_p11_challenge(char *challenge); 256 241 gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_); … … 266 251 const struct msn_status_code *msn_status_by_number(int number); 267 252 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); 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); 274 266 275 267 #endif //_MSN_H -
protocols/msn/msn_util.c
rb1dc403 r531eabd 55 55 56 56 *groupid = '\0'; 57 #if 0 58 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 a 92 new group at once; we're still waiting for the server 93 to confirm group creation. */ 94 return 1; 95 } 96 } 97 } 98 #endif 57 99 58 100 if (!((bu = bee_user_by_handle(ic->bee, ic, who)) || … … 90 132 91 133 *groupid = '\0'; 134 #if 0 135 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 #endif 92 145 93 146 if (!(bu = bee_user_by_handle(ic->bee, ic, who)) || … … 121 174 }; 122 175 123 static void msn_buddy_ask_ free(void *data)176 static void msn_buddy_ask_yes(void *data) 124 177 { 125 178 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); 126 183 127 184 g_free(bla->handle); … … 130 187 } 131 188 132 static void msn_buddy_ask_ yes(void *data)189 static void msn_buddy_ask_no(void *data) 133 190 { 134 191 struct msn_buddy_ask_data *bla = data; 135 192 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 143 static void msn_buddy_ask_no(void *data)144 {145 struct msn_buddy_ask_data *bla = data;146 147 193 msn_buddy_list_add(bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL); 148 194 149 msn_buddy_ask_free(bla); 195 g_free(bla->handle); 196 g_free(bla->realname); 197 g_free(bla); 150 198 } 151 199 … … 168 216 "The user %s (%s) wants to add you to his/her buddy list.", 169 217 bu->handle, bu->fullname); 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 } 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); 185 252 } 186 253 … … 193 260 1: OK */ 194 261 195 int msn_handler(struct msn_data *h) 196 { 197 int st = 1; 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 } 198 278 199 279 while (st) { … … 207 287 208 288 cmd_text = g_strndup(h->rxq, i); 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); 289 cmd = msn_linesplit(cmd_text); 290 for (count = 0; cmd[count]; count++) { 291 ; 292 } 293 st = h->exec_command(h, cmd, count); 215 294 g_free(cmd_text); 216 295 … … 235 314 /* If we reached the end of the buffer, there's still an incomplete command there. 236 315 Return and wait for more data. */ 237 if (i && i== h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') {316 if (i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') { 238 317 break; 239 318 } … … 248 327 249 328 msg = g_strndup(h->rxq, h->msglen); 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); 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); 257 335 g_free(msg); 258 336 g_free(h->cmd_text); … … 288 366 } 289 367 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 290 408 /* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ 291 409 char *msn_p11_challenge(char *challenge) … … 411 529 int msn_ns_set_display_name(struct im_connection *ic, const char *value) 412 530 { 413 // TODO, implement this through msn_set_away's method 414 return 1; 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); 415 540 } 416 541 -
protocols/msn/ns.c
rb1dc403 r531eabd 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); 37 39 38 40 static void msn_ns_send_adl_start(struct im_connection *ic); 39 41 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);43 42 44 43 int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) … … 55 54 56 55 if (fd < 0) { 57 fd = md-> fd;56 fd = md->ns->fd; 58 57 } 59 58 60 59 if (getenv("BITLBEE_DEBUG")) { 61 fprintf(stderr, " \x1b[91m>>>[NS%d] %s\n\x1b[97m", fd, out);60 fprintf(stderr, "->NS%d:%s\n", fd, out); 62 61 } 63 62 64 63 len = strlen(out); 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 64 st = write(fd, out, len); 73 65 g_free(out); 74 66 if (st != len) { … … 81 73 } 82 74 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) { 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) { 113 86 imcb_error(ic, "Could not connect to server"); 114 87 imc_logout(ic, TRUE); … … 116 89 } 117 90 118 g_free(md->rxq); 119 md->rxlen = 0; 120 md->rxq = g_new0(char, 1); 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); 121 115 122 116 if (md->uuid == NULL) { … … 136 130 137 131 if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER)) { 138 if (!md->is_http) { 139 md->inpa = b_input_add(md->fd, B_EV_IO_READ, msn_ns_callback, md); 140 } 132 handler->inpa = b_input_add(handler->fd, B_EV_IO_READ, msn_ns_callback, handler); 141 133 imcb_log(ic, "Connected to server, waiting for reply"); 142 134 } … … 145 137 } 146 138 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; 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; 164 153 } 165 154 166 155 static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond) 167 156 { 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) { 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. */ 181 161 imcb_error(ic, "Error while reading from server"); 182 162 imc_logout(ic, TRUE); 163 183 164 return FALSE; 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; 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; 200 174 201 175 if (num_parts == 0) { … … 211 185 } 212 186 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",187 return(msn_ns_write(ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", 214 188 ++md->trId, ic->acc->user)); 215 189 } else if (strcmp(cmd[0], "CVR") == 0) { 216 190 /* We don't give a damn about the information we just received */ 217 return msn_ns_write(ic, md->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);191 return msn_ns_write(ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user); 218 192 } else if (strcmp(cmd[0], "XFR") == 0) { 219 193 char *server; … … 221 195 222 196 if (num_parts >= 6 && strcmp(cmd[2], "NS") == 0) { 223 b_event_remove( md->inpa);224 md->inpa = -1;197 b_event_remove(handler->inpa); 198 handler->inpa = -1; 225 199 226 200 server = strchr(cmd[3], ':'); … … 235 209 236 210 imcb_log(ic, "Transferring to other server"); 237 return msn_ns_connect(ic, server, port); 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 } 238 259 } else { 239 260 imcb_error(ic, "Syntax error"); … … 269 290 } 270 291 271 md->msglen = atoi(cmd[3]);272 273 if ( md->msglen <= 0) {292 handler->msglen = atoi(cmd[3]); 293 294 if (handler->msglen <= 0) { 274 295 imcb_error(ic, "Syntax error"); 275 296 imc_logout(ic, TRUE); 276 297 return(0); 277 298 } 299 } else if (strcmp(cmd[0], "BLP") == 0) { 300 msn_ns_send_adl_start(ic); 301 return msn_ns_finish_login(ic); 278 302 } else if (strcmp(cmd[0], "ADL") == 0) { 279 303 if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) { … … 281 305 return msn_ns_finish_login(ic); 282 306 } else if (num_parts >= 3) { 283 md->msglen = atoi(cmd[2]); 284 } 307 handler->msglen = atoi(cmd[2]); 308 } 309 } else if (strcmp(cmd[0], "PRP") == 0) { 310 imcb_connected(ic); 285 311 } else if (strcmp(cmd[0], "CHL") == 0) { 286 312 char *resp; … … 300 326 g_free(resp); 301 327 return st; 302 } else if (strcmp(cmd[0], "QRY") == 0) { 303 /* CONGRATULATIONS */ 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 } 304 417 } else if (strcmp(cmd[0], "OUT") == 0) { 305 imcb_error(ic, "Session terminated by remote server (%s)", cmd[1] ? cmd[1] : "reason unknown"); 306 imc_logout(ic, TRUE); 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); 307 431 return(0); 308 } else if (strcmp(cmd[0], "GCF") == 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) { 309 485 /* Coming up is cmd[2] bytes of stuff we're supposed to 310 486 censore. Meh. */ 311 md->msglen = atoi(cmd[2]); 312 } else if ((strcmp(cmd[0], "NFY") == 0) || (strcmp(cmd[0], "SDG") == 0)) { 487 handler->msglen = atoi(cmd[2]); 488 } else if (strcmp(cmd[0], "UBX") == 0) { 489 /* Status message. */ 313 490 if (num_parts >= 3) { 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]); 491 handler->msglen = atoi(cmd[2]); 319 492 } 320 493 } else if (strcmp(cmd[0], "NOT") == 0) { 494 /* Some kind of notification, poorly documented but 495 apparently used to announce address book changes. */ 321 496 if (num_parts >= 2) { 322 md->msglen = atoi(cmd[1]); 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]); 323 502 } 324 503 } else if (strcmp(cmd[0], "QNG") == 0) { … … 337 516 /* Oh yes, errors can have payloads too now. Discard them for now. */ 338 517 if (num_parts >= 3) { 339 md->msglen = atoi(cmd[2]);518 handler->msglen = atoi(cmd[2]); 340 519 } 341 520 } else { 342 imcb_error(ic, "Received unknown command from main server: %s", cmd[0]);521 /* debug( "Received unknown command from main server: %s", cmd[0] ); */ 343 522 } 344 523 … … 346 525 } 347 526 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;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; 351 530 char *body; 352 531 int blen = 0; … … 419 598 } 420 599 } else if (g_strncasecmp(ct, "text/x-msmsgsactivemailnotification", 35) == 0) { 421 /* Notification that a message has been read... Ignore it */ 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); 422 652 } else { 423 653 debug("Can't handle %s packet from notification server", ct); … … 426 656 g_free(ct); 427 657 } 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); 428 670 } else if (strcmp(cmd[0], "ADL") == 0) { 429 671 struct xt_node *adl, *d, *c; … … 474 716 } 475 717 } 476 } else if ((strcmp(cmd[0], "SDG") == 0) || (strcmp(cmd[0], "NFY") == 0)) { 477 msn_ns_structured_message(md, msg, msglen, cmd); 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); 478 744 } 479 745 480 746 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);586 747 } 587 748 … … 607 768 void msn_auth_got_contact_list(struct im_connection *ic) 608 769 { 770 struct msn_data *md; 771 609 772 /* Dead connection? */ 610 773 if (g_slist_find(msn_connections, ic) == NULL) { … … 612 775 } 613 776 614 m sn_ns_send_adl_start(ic);615 msn_ns_ finish_login(ic);777 md = ic->proto_data; 778 msn_ns_write(ic, -1, "BLP %d %s\r\n", ++md->trId, "BL"); 616 779 } 617 780 618 781 static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data) 619 782 { 620 struct xt_node *adl = data, *d, *c , *s;783 struct xt_node *adl = data, *d, *c; 621 784 struct bee_user *bu = value; 622 785 struct msn_buddy_data *bd = bu->data; … … 647 810 c = xt_new_node("c", NULL, NULL); 648 811 xt_add_attr(c, "n", handle); 812 xt_add_attr(c, "l", l); 649 813 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);654 814 xt_insert_child(d, c); 655 815 … … 721 881 722 882 if ((md->flags & MSN_DONE_ADL) && (md->flags & MSN_GOT_PROFILE)) { 723 imcb_connected(ic); 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 } 724 888 } 725 889 … … 727 891 } 728 892 729 // TODO: typing notifications, nudges lol, etc730 893 int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text) 731 894 { 732 895 struct msn_data *md = ic->proto_data; 733 int retval= 0;734 char *buf ;896 int type = 0; 897 char *buf, *handle; 735 898 736 899 if (strncmp(text, "\r\r\r", 3) == 0) { … … 740 903 } 741 904 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 } 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 } -
protocols/msn/soap.c
rb1dc403 r531eabd 209 209 return; 210 210 } 211 fprintf(stderr, "\n\x1b[90mSOAP:\n");212 211 213 212 if (headers) { … … 226 225 xt_free_node(xt); 227 226 } 228 fprintf(stderr, "\n\x1b[97m\n");229 227 } 230 228 -
protocols/msn/soap.h
rb1dc403 r531eabd 167 167 168 168 #define SOAP_MEMLIST_PAYLOAD \ 169 "<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\"><serviceFilter ><Types><ServiceType>Messenger</ServiceType><ServiceType>IMAvailability</ServiceType></Types></serviceFilter><expandMembership>true</expandMembership>" \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>" \ 170 170 "</FindMembership>" 171 171 -
protocols/msn/tables.c
rb1dc403 r531eabd 73 73 { 206, "Domain name missing", 0 }, 74 74 { 207, "Already logged in", 0 }, 75 { 208, "Invalid handle", 0},75 { 208, "Invalid handle", STATUS_SB_IM_SPARE }, 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", 0},80 { 217, "Person is off-line or non-existent", 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 }, 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", 0},115 { 713, "Calling too rapidly", STATUS_SB_IM_SPARE }, 116 116 { 714, "Too many sessions", STATUS_FATAL }, 117 117 { 715, "Not expected/Invalid argument/action", 0 }, -
protocols/nogaim.c
rb1dc403 r531eabd 503 503 }; 504 504 505 static void imcb_ask_ cb_free(void *data)505 static void imcb_ask_auth_cb_no(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); 508 510 509 511 g_free(cbd->handle); … … 511 513 } 512 514 513 static void imcb_ask_auth_cb_ no(void *data)515 static void imcb_ask_auth_cb_yes(void *data) 514 516 { 515 517 struct imcb_ask_cb_data *cbd = data; 516 518 517 cbd->ic->acc->prpl->auth_deny(cbd->ic, cbd->handle);518 519 imcb_ask_cb_free(cbd);520 }521 522 static void imcb_ask_auth_cb_yes(void *data)523 {524 struct imcb_ask_cb_data *cbd = data;525 526 519 cbd->ic->acc->prpl->auth_allow(cbd->ic, cbd->handle); 527 520 528 imcb_ask_cb_free(cbd); 521 g_free(cbd->handle); 522 g_free(cbd); 529 523 } 530 524 … … 546 540 data->handle = g_strdup(handle); 547 541 query_add((irc_t *) ic->bee->ui_data, ic, s, 548 imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, imcb_ask_cb_free, data); 549 550 g_free(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); 551 550 } 552 551 … … 557 556 cbd->ic->acc->prpl->add_buddy(cbd->ic, cbd->handle, NULL); 558 557 559 imcb_ask_ cb_free(data);558 imcb_ask_add_cb_no(data); 560 559 } 561 560 562 561 void imcb_ask_add(struct im_connection *ic, const char *handle, const char *realname) 563 562 { 564 struct imcb_ask_cb_data *data ;563 struct imcb_ask_cb_data *data = g_new0(struct imcb_ask_cb_data, 1); 565 564 char *s; 566 565 … … 570 569 } 571 570 572 data = g_new0(struct imcb_ask_cb_data, 1);573 574 571 s = g_strdup_printf("The user %s is not in your buddy list yet. Do you want to add him/her now?", handle); 575 572 … … 577 574 data->handle = g_strdup(handle); 578 575 query_add((irc_t *) ic->bee->ui_data, ic, s, 579 imcb_ask_add_cb_yes, imcb_ask_cb_free, imcb_ask_cb_free, data); 580 581 g_free(s); 576 imcb_ask_add_cb_yes, imcb_ask_add_cb_no, g_free, data); 582 577 } 583 578 -
protocols/purple/ft-direct.c
rb1dc403 r531eabd 28 28 29 29 #include "bitlbee.h" 30 #include "bpurple.h"31 30 32 31 #include <stdarg.h> … … 208 207 void purple_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *handle) 209 208 { 210 struct purple_data *pd= ic->proto_data;209 PurpleAccount *pa = ic->proto_data; 211 210 struct prpl_xfer_data *px; 212 211 … … 214 213 multi-threaded anyway. */ 215 214 next_ft = ft; 216 serv_send_file(purple_account_get_connection(pd->account), handle, 217 ft->file_name); 215 serv_send_file(purple_account_get_connection(pa), handle, ft->file_name); 218 216 219 217 ft->write = prpl_xfer_write; -
protocols/purple/ft.c
rb1dc403 r531eabd 28 28 29 29 #include "bitlbee.h" 30 #include "bpurple.h"31 30 32 31 #include <stdarg.h> … … 286 285 { 287 286 struct prpl_xfer_data *px = ft->data; 288 struct purple_data *pd= px->ic->proto_data;287 PurpleAccount *pa = px->ic->proto_data; 289 288 290 289 /* xfer_new() will pick up this variable. It's a hack but we're not 291 290 multi-threaded anyway. */ 292 291 next_ft = ft; 293 serv_send_file(purple_account_get_connection(pd->account), 294 px->handle, px->fn); 292 serv_send_file(purple_account_get_connection(pa), px->handle, px->fn); 295 293 } 296 294 -
protocols/purple/purple.c
rb1dc403 r531eabd 23 23 24 24 #include "bitlbee.h" 25 #include "bpurple.h"26 25 #include "help.h" 27 26 … … 40 39 static char *set_eval_display_name(set_t *set, char *value); 41 40 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 56 41 struct im_connection *purple_ic_by_pa(PurpleAccount *pa) 57 42 { 58 43 GSList *i; 59 struct purple_data *pd;60 44 61 45 for (i = purple_connections; i; i = i->next) { 62 pd = ((struct im_connection *) i->data)->proto_data; 63 if (pd->account == pa) { 46 if (((struct im_connection *) i->data)->proto_data == pa) { 64 47 return i->data; 65 48 } … … 307 290 { 308 291 struct im_connection *ic = imcb_new(acc); 309 struct purple_data *pd;292 PurpleAccount *pa; 310 293 311 294 if ((local_bee != NULL && local_bee != acc->bee) || … … 323 306 purple_connections = g_slist_prepend(purple_connections, ic); 324 307 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); 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); 334 313 } 335 314 336 315 static void purple_logout(struct im_connection *ic) 337 316 { 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); 317 PurpleAccount *pa = ic->proto_data; 318 319 purple_account_set_enabled(pa, "BitlBee", FALSE); 345 320 purple_connections = g_slist_remove(purple_connections, ic); 346 purple_accounts_remove(pd->account); 347 g_hash_table_destroy(pd->input_requests); 348 g_free(pd); 321 purple_accounts_remove(pa); 349 322 } 350 323 … … 352 325 { 353 326 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 }361 327 362 328 if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, 363 who, pd->account)) == NULL) {329 who, ic->proto_data)) == NULL) { 364 330 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, 365 pd->account, who);331 ic->proto_data, who); 366 332 } 367 333 … … 373 339 static GList *purple_away_states(struct im_connection *ic) 374 340 { 375 struct purple_data *pd= ic->proto_data;341 PurpleAccount *pa = ic->proto_data; 376 342 GList *st, *ret = NULL; 377 343 378 for (st = purple_account_get_status_types(p d->account); st; st = st->next) {344 for (st = purple_account_get_status_types(pa); st; st = st->next) { 379 345 PurpleStatusPrimitive prim = purple_status_type_get_primitive(st->data); 380 346 if (prim != PURPLE_STATUS_AVAILABLE && prim != PURPLE_STATUS_OFFLINE) { … … 388 354 static void purple_set_away(struct im_connection *ic, char *state_txt, char *message) 389 355 { 390 struct purple_data *pd= ic->proto_data;391 GList *status_types = purple_account_get_status_types(p d->account), *st;356 PurpleAccount *pa = ic->proto_data; 357 GList *status_types = purple_account_get_status_types(pa), *st; 392 358 PurpleStatusType *pst = NULL; 393 359 GList *args = NULL; … … 412 378 } 413 379 414 purple_account_set_status_list(pd->account, 415 st ? purple_status_type_get_id(pst) : "away", 380 purple_account_set_status_list(pa, st ? purple_status_type_get_id(pst) : "away", 416 381 TRUE, args); 417 382 … … 482 447 PurpleBuddy *pb; 483 448 PurpleGroup *pg = NULL; 484 struct purple_data *pd = ic->proto_data;485 449 486 450 if (group && !(pg = purple_find_group(group))) { … … 489 453 } 490 454 491 pb = purple_buddy_new( pd->account, who, NULL);455 pb = purple_buddy_new((PurpleAccount *) ic->proto_data, who, NULL); 492 456 purple_blist_add_buddy(pb, NULL, pg, NULL); 493 purple_account_add_buddy( pd->account, pb);494 495 purple_gg_buddylist_export( pd->account->gc);457 purple_account_add_buddy((PurpleAccount *) ic->proto_data, pb); 458 459 purple_gg_buddylist_export(((PurpleAccount *) ic->proto_data)->gc); 496 460 } 497 461 … … 499 463 { 500 464 PurpleBuddy *pb; 501 struct purple_data *pd = ic->proto_data; 502 503 pb = purple_find_buddy(pd->account, who); 465 466 pb = purple_find_buddy((PurpleAccount *) ic->proto_data, who); 504 467 if (pb != NULL) { 505 468 PurpleGroup *group; 506 469 507 470 group = purple_buddy_get_group(pb); 508 purple_account_remove_buddy( pd->account, pb, group);471 purple_account_remove_buddy((PurpleAccount *) ic->proto_data, pb, group); 509 472 510 473 purple_blist_remove_buddy(pb); 511 474 } 512 475 513 purple_gg_buddylist_export( pd->account->gc);476 purple_gg_buddylist_export(((PurpleAccount *) ic->proto_data)->gc); 514 477 } 515 478 516 479 static void purple_add_permit(struct im_connection *ic, char *who) 517 480 { 518 struct purple_data *pd= ic->proto_data;519 520 purple_privacy_permit_add(p d->account, who, FALSE);481 PurpleAccount *pa = ic->proto_data; 482 483 purple_privacy_permit_add(pa, who, FALSE); 521 484 } 522 485 523 486 static void purple_add_deny(struct im_connection *ic, char *who) 524 487 { 525 struct purple_data *pd= ic->proto_data;526 527 purple_privacy_deny_add(p d->account, who, FALSE);488 PurpleAccount *pa = ic->proto_data; 489 490 purple_privacy_deny_add(pa, who, FALSE); 528 491 } 529 492 530 493 static void purple_rem_permit(struct im_connection *ic, char *who) 531 494 { 532 struct purple_data *pd= ic->proto_data;533 534 purple_privacy_permit_remove(p d->account, who, FALSE);495 PurpleAccount *pa = ic->proto_data; 496 497 purple_privacy_permit_remove(pa, who, FALSE); 535 498 } 536 499 537 500 static void purple_rem_deny(struct im_connection *ic, char *who) 538 501 { 539 struct purple_data *pd= ic->proto_data;540 541 purple_privacy_deny_remove(p d->account, who, FALSE);502 PurpleAccount *pa = ic->proto_data; 503 504 purple_privacy_deny_remove(pa, who, FALSE); 542 505 } 543 506 544 507 static void purple_get_info(struct im_connection *ic, char *who) 545 508 { 546 struct purple_data *pd = ic->proto_data; 547 548 serv_get_info(purple_account_get_connection(pd->account), who); 509 serv_get_info(purple_account_get_connection(ic->proto_data), who); 549 510 } 550 511 … … 556 517 { 557 518 PurpleTypingState state = PURPLE_NOT_TYPING; 558 struct purple_data *pd= ic->proto_data;519 PurpleAccount *pa = ic->proto_data; 559 520 560 521 if (flags & OPT_TYPING) { … … 564 525 } 565 526 566 serv_send_typing(purple_account_get_connection(p d->account), who, state);527 serv_send_typing(purple_account_get_connection(pa), who, state); 567 528 568 529 return 1; … … 598 559 /* There went my nice afternoon. :-( */ 599 560 600 struct purple_data *pd= ic->proto_data;601 PurplePlugin *prpl = purple_plugins_find_with_id(p d->account->protocol_id);561 PurpleAccount *pa = ic->proto_data; 562 PurplePlugin *prpl = purple_plugins_find_with_id(pa->protocol_id); 602 563 PurplePluginProtocolInfo *pi = prpl->info->extra_info; 603 PurpleBuddy *pb = purple_find_buddy( pd->account, who);564 PurpleBuddy *pb = purple_find_buddy((PurpleAccount *) ic->proto_data, who); 604 565 PurpleMenuAction *mi; 605 566 GList *menu; … … 636 597 PurpleConversation *pc = gc->data; 637 598 PurpleConvChat *pcc = PURPLE_CONV_CHAT(pc); 638 struct purple_data *pd = gc->ic->proto_data; 639 640 serv_chat_invite(purple_account_get_connection(pd->account), 599 600 serv_chat_invite(purple_account_get_connection(gc->ic->proto_data), 641 601 purple_conv_chat_get_id(pcc), 642 602 message && *message ? message : "Please join my chat", … … 663 623 set_t **sets) 664 624 { 665 struct purple_data *pd= ic->proto_data;666 PurplePlugin *prpl = purple_plugins_find_with_id(p d->account->protocol_id);625 PurpleAccount *pa = ic->proto_data; 626 PurplePlugin *prpl = purple_plugins_find_with_id(pa->protocol_id); 667 627 PurplePluginProtocolInfo *pi = prpl->info->extra_info; 668 628 GHashTable *chat_hash; … … 671 631 672 632 if (!pi->chat_info || !pi->chat_info_defaults || 673 !(info = pi->chat_info(purple_account_get_connection(p d->account)))) {633 !(info = pi->chat_info(purple_account_get_connection(pa)))) { 674 634 imcb_error(ic, "Joining chatrooms not supported by this protocol"); 675 635 return NULL; 676 636 } 677 637 678 if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 679 room, pd->account))) { 638 if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, room, pa))) { 680 639 purple_conversation_destroy(conv); 681 640 } 682 641 683 chat_hash = pi->chat_info_defaults( 684 purple_account_get_connection(pd->account), room 685 ); 642 chat_hash = pi->chat_info_defaults(purple_account_get_connection(pa), room); 686 643 687 644 for (l = info; l; l = l->next) { … … 697 654 } 698 655 699 serv_join_chat(purple_account_get_connection(p d->account), chat_hash);656 serv_join_chat(purple_account_get_connection(pa), chat_hash); 700 657 701 658 return NULL; … … 1024 981 pqad->yes(pqad->user_data, pqad->yes_i); 1025 982 } 983 g_free(pqad); 1026 984 } 1027 985 … … 1033 991 pqad->no(pqad->user_data, pqad->no_i); 1034 992 } 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); 993 g_free(pqad); 1044 994 } 1045 995 … … 1076 1026 q = g_strdup_printf("Request: %s\n\n%s\n\n%s", title, primary, secondary); 1077 1027 pqad->bee_data = query_add(local_bee->ui_data, purple_ic_by_pa(account), q, 1078 prplcb_request_action_yes, prplcb_request_action_no, 1079 prplcb_request_action_free, pqad); 1028 prplcb_request_action_yes, prplcb_request_action_no, g_free, pqad); 1080 1029 1081 1030 g_free(q); … … 1084 1033 } 1085 1034 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 1035 /* 1036 static void prplcb_request_test() 1037 { 1038 fprintf( stderr, "bla\n" ); 1039 } 1040 */ 1162 1041 1163 1042 static PurpleRequestUiOps bee_request_uiops = 1164 1043 { 1165 prplcb_request_input,1044 NULL, 1166 1045 NULL, 1167 1046 prplcb_request_action, 1168 1047 NULL, 1169 1048 NULL, 1170 prplcb_close_request,1049 NULL, 1171 1050 NULL, 1172 1051 }; -
protocols/skype/Makefile
rb1dc403 r531eabd 6 6 DATE := $(shell date +%Y-%m-%d) 7 7 INSTALL = install 8 ASCIIDOC = yes 8 9 9 10 ifdef ASCIIDOC 10 ifeq ($(ASCIIDOC),yes) 11 11 MANPAGES = skyped.1 12 12 else … … 29 29 30 30 install-doc: doc 31 if def ASCIIDOC31 ifeq ($(ASCIIDOC),yes) 32 32 $(INSTALL) -d $(DESTDIR)$(MANDIR)/man1 33 33 $(INSTALL) -m644 $(MANPAGES) $(DESTDIR)$(MANDIR)/man1 -
protocols/twitter/twitter.c
rb1dc403 r531eabd 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 871 854 /** Convert the given bitlbee tweet ID, bitlbee username, or twitter tweet ID 872 855 * into a twitter tweet ID. … … 896 879 arg++; 897 880 } 898 if (twitter_parse_id(arg, 16, &id) && id < TWITTER_LOG_LENGTH) { 881 if (sscanf(arg, "%" G_GINT64_MODIFIER "x", &id) == 1 && 882 id < TWITTER_LOG_LENGTH) { 899 883 bu = td->log[id].bu; 900 884 id = td->log[id].id; 901 } else if (twitter_parse_id(arg, 10, &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) { 902 890 /* Allow normal tweet IDs as well; not a very useful 903 891 feature but it's always been there. Just ignore … … 909 897 } 910 898 if (bu_) { 911 if (bu == &twitter_log_local_user) {912 /* HACK alert. There's no bee_user object for the local913 * 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 }921 899 *bu_ = bu; 922 900 } … … 1011 989 in_reply_to = id; 1012 990 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's1019 * 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 of1021 * the original message. */1022 twitter_log(ic, "https://twitter.com/statuses/%lld", id);1023 }1024 goto eof;1025 1026 991 } else if (g_strcasecmp(cmd[0], "post") == 0) { 1027 992 message += 5; -
protocols/twitter/twitter.h
rb1dc403 r531eabd 101 101 struct twitter_log_data { 102 102 guint64 id; 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; 103 struct bee_user *bu; /* DANGER: can be a dead pointer. Check it first. */ 106 104 }; 107 105 … … 112 110 */ 113 111 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 BitlBee119 * threaded. :-)120 */121 extern bee_user_t twitter_log_local_user;122 112 123 113 void twitter_login_finish(struct im_connection *ic); -
protocols/twitter/twitter_lib.c
rb1dc403 r531eabd 460 460 #endif 461 461 462 static void expand_entities(char **text, const json_value *node);462 static char* expand_entities(char* text, const json_value *entities); 463 463 464 464 /** … … 473 473 { 474 474 struct twitter_xml_status *txs; 475 const json_value *rt = NULL ;475 const json_value *rt = NULL, *entities = 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; 503 505 } 504 506 } … … 514 516 txs_free(rtxs); 515 517 } 516 } else {517 expand_entities(&txs->text, node);518 } else if (entities) { 519 txs->text = expand_entities(txs->text, entities); 518 520 } 519 521 … … 532 534 { 533 535 struct twitter_xml_status *txs; 536 const json_value *entities = NULL; 534 537 535 538 if (node->type != json_object) { … … 558 561 } 559 562 560 expand_entities(&txs->text, node); 563 if (entities) { 564 txs->text = expand_entities(txs->text, entities); 565 } 561 566 562 567 if (txs->text && txs->user && txs->id) { … … 568 573 } 569 574 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 575 static char* expand_entities(char* text, const json_value *entities) 576 { 590 577 JSON_O_FOREACH(entities, k, v) { 591 578 int i; … … 599 586 600 587 for (i = 0; i < v->u.array.length; i++) { 601 const char *format = "%s%s <%s>%s";602 603 588 if (v->u.array.values[i]->type != json_object) { 604 589 continue; … … 607 592 const char *kort = json_o_str(v->u.array.values[i], "url"); 608 593 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");610 594 char *pos, *new; 611 595 612 if (!kort || !disp || !(pos = strstr( *text, kort))) {596 if (!kort || !disp || !(pos = strstr(text, kort))) { 613 597 continue; 614 598 } 615 if (quote_url && strstr(full, quote_url)) {616 format = "%s<%s> [%s]%s";617 disp = quote_text;618 }619 599 620 600 *pos = '\0'; 621 new = g_strdup_printf( format, *text, kort,601 new = g_strdup_printf("%s%s <%s>%s", text, kort, 622 602 disp, pos + strlen(kort)); 623 603 624 g_free( *text);625 *text = new;626 } 627 } 628 g_free(quote_text); 629 g_free(quote_url);604 g_free(text); 605 text = new; 606 } 607 } 608 609 return text; 630 610 } 631 611 … … 701 681 if (g_strcasecmp(txs->user->screen_name, td->user) == 0) { 702 682 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;705 683 } 706 684 … … 854 832 855 833 last_id_str = g_strdup_printf("%" G_GUINT64_FORMAT, td->timeline_id); 856 set_setstr(&ic->acc->set, " _last_tweet", last_id_str);834 set_setstr(&ic->acc->set, "last_tweet", last_id_str); 857 835 g_free(last_id_str); 858 836 } … … 884 862 885 863 imcb_error(ic, "Stream closed (%s)", req->status_string); 886 if (req->status_code == 401) {887 imcb_error(ic, "Check your system clock.");888 }889 864 imc_logout(ic, TRUE); 890 865 return; -
protocols/yahoo/yahoo.c
rb1dc403 r531eabd 733 733 inp = l->data; 734 734 if (inp->h == tag) { 735 byahoo_inputs = g_slist_remove(byahoo_inputs, inp);736 735 g_free(inp->d); 737 736 g_free(inp); 737 byahoo_inputs = g_slist_remove(byahoo_inputs, inp); 738 738 break; 739 739 } -
storage_xml.c
rb1dc403 r531eabd 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 }109 105 local = protocol_account_islocal(protocol); 110 106 } … … 128 124 } 129 125 } else { 130 g_free(pass_cr);131 g_free(password);132 126 return XT_ABORT; 133 127 } … … 203 197 fn = g_strconcat(global.conf->configdir, xd->given_nick, ".xml", NULL); 204 198 if ((fd = open(fn, O_RDONLY)) < 0) { 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 } 199 ret = STORAGE_NO_SUCH_USER; 210 200 goto error; 211 201 } … … 269 259 270 260 261 static gboolean xml_generate_nick(gpointer key, gpointer value, gpointer data); 271 262 static void xml_generate_settings(struct xt_node *cur, set_t **head); 272 263 … … 301 292 302 293 for (acc = irc->b->accounts; acc; acc = acc->next) { 303 GHashTableIter iter;304 gpointer key, value;305 294 unsigned char *pass_cr; 306 295 char *pass_b64; … … 323 312 g_free(pass_b64); 324 313 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 } 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); 332 322 333 323 xml_generate_settings(cur, &acc->set); … … 353 343 354 344 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; 355 356 } 356 357 … … 387 388 strcat(path, ".XXXXXX"); 388 389 if ((fd = mkstemp(path)) < 0) { 389 goto error; 390 irc_rootmsg(irc, "Error while opening configuration file."); 391 return STORAGE_OTHER_ERROR; 390 392 } 391 393 … … 409 411 410 412 error: 411 irc_rootmsg(irc, "Write error : %s", g_strerror(errno));413 irc_rootmsg(irc, "Write error. Disk full?"); 412 414 ret = STORAGE_OTHER_ERROR; 413 415
Note: See TracChangeset
for help on using the changeset viewer.