Changes in / [b1dc403:531eabd]


Ignore:
Files:
3 added
3 deleted
49 edited

Legend:

Unmodified
Added
Removed
  • .travis.yml

    rb1dc403 r531eabd  
    11language: c
    2 
    3 script:
    4  - ./configure
    5  - make check
    6  - dpkg-buildpackage -uc -us
    7 
     2script: ./configure && make check && dpkg-buildpackage -uc -us
    83before_install:
    94 - sudo apt-get update -qq
     
    127 - sudo dpkg -i *.deb
    138
    14 env:
    15   global:
    16    # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
    17    #   via the "travis encrypt" command using the project repo's public key
    18    - secure: "MO6hy2cRxR02A0nSenfQFyPFpepxorJ+XgNkq2JS7LtI6tcwYRR0alvunIPJXam1/OUKxoFsBJLS1nCJTvEUXFCOvoTSAoMiePTBUEg2zfzcTb5k+cqtcOUznCXHNmXAwrqriP4vkG+57ijO9Ojz2r9LijcvjtFDRFJQY9Rcs38="
    19 
    20 addons:
    21   coverity_scan:
    22     project:
    23       name: "bitlbee/bitlbee"
    24       description: "An IRC to other chat networks gateway"
    25     notification_email: dx@dxzone.com.ar
    26     build_command_prepend: ./configure --otr=1 --debug=1
    27     build_command: make
    28     branch_pattern: coverity_scan
    29 
    30 notifications:
    31   email: false
  • Makefile

    rb1dc403 r531eabd  
    2525
    2626doc:
    27 ifdef DOC
    2827        $(MAKE) -C doc
    29 endif
    3028
    3129uninstall: uninstall-bin uninstall-doc
     
    7573
    7674install-doc:
    77 ifdef DOC
    7875        $(MAKE) -C doc install
    79 endif
    8076ifdef SKYPE_PI
    8177        $(MAKE) -C protocols/skype install-doc
     
    8379
    8480uninstall-doc:
    85 ifdef DOC
    8681        $(MAKE) -C doc uninstall
    87 endif
    8882ifdef SKYPE_PI
    8983        $(MAKE) -C protocols/skype uninstall-doc
     
    159153        x=$$(basename $$(pwd)); \
    160154        cd ..; \
    161         tar czf $$x.tar.gz --exclude=debian --exclude=.git* --exclude=.depend $$x
     155        tar czf $$x.tar.gz --exclude-from=.gitignore $$x
    162156
    163157$(subdirs):
  • bitlbee.h

    rb1dc403 r531eabd  
    3636
    3737#define PACKAGE "BitlBee"
    38 #define BITLBEE_VERSION "3.4"
     38#define BITLBEE_VERSION "3.2.2"
    3939#define VERSION BITLBEE_VERSION
    4040#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)
    4242
    4343#define MAX_STRING 511
  • configure

    rb1dc403 r531eabd  
    3838purple=0
    3939
    40 doc=1
    4140debug=0
    4241strip=1
     
    5756GLIB_MIN_VERSION=2.16
    5857
     58echo BitlBee configure
     59
    5960# Cygwin and Darwin don't support PIC/PIE
    6061case "$arch" in
    61         CYGWIN* )
    62                 pie=0;;
    63         Darwin )
    64                 pie=0;;
     62    CYGWIN* )
     63        pie=0;;
     64    Darwin )
     65        pie=0;;
    6566esac
    66 
    67 get_version() {
    68         REAL_BITLBEE_VERSION=$(grep '^#define BITLBEE_VERSION ' $srcdir/bitlbee.h | sed 's/.*\"\(.*\)\".*/\1/')
    69         BITLBEE_VERSION=$REAL_BITLBEE_VERSION
    70 
    71         if [ -d $srcdir/.git ] && type git > /dev/null 2> /dev/null; then
    72                 timestamp=$(cd $srcdir; git show -s --format=%ci HEAD | sed 's/ .*$//; s/-//g')
    73                 branch=$(cd $srcdir; git rev-parse --abbrev-ref HEAD)
    74 
    75                 search="(.+)-([0-9]+)-(g[0-9a-f]+)"
    76                 replace="\1+$timestamp+$branch+\2-\3-git"
    77 
    78                 BITLBEE_VERSION=$(cd $srcdir; git describe --long --tags | sed -r "s/$search/$replace/")
    79 
    80                 unset timestamp branch search replace
    81         fi
    82 }
    83 
    84 if [ "$1" = "--dump-version" ]; then
    85         srcdir=$(cd $(dirname $0);pwd)
    86         get_version
    87         echo $BITLBEE_VERSION
    88         exit
    89 fi
    90 
    91 echo BitlBee configure
    9267
    9368while [ -n "$1" ]; do
     
    12196--rpc=0/1       Disable/enable RPC interface            $rpc
    12297
    123 --doc=0/1       Disable/enable help.txt generation      $doc
    12498--debug=0/1     Disable/enable debugging                $debug
    12599--strip=0/1     Disable/enable binary stripping         $strip
     
    476450        ret=1
    477451        echo "$RESOLV_NS_TESTCODE" | $CC -o $TMPFILE -x c - $LIBRESOLV >/dev/null 2>/dev/null
    478         if [ "$?" = "0" ]; then
    479                 ret=0
    480         fi
     452        if [ "$?" = "0" ]; then
     453                ret=0
     454        fi
    481455
    482456        rm -f $TMPFILE
     
    491465                if [ -f $i/libresolv.a ]; then
    492466                        echo "$RESOLV_NS_TESTCODE" | $CC -o $TMPFILE -x c - -Wl,$i/libresolv.a >/dev/null 2>/dev/null
    493                         if [ "$?" = "0" ]; then
    494                                 ret=0
    495                         fi
     467                        if [ "$?" = "0" ]; then
     468                                ret=0
     469                        fi
    496470                fi
    497471        done
     
    503477detect_nameser_has_ns_types()
    504478{
    505         TMPFILE=$(mktemp /tmp/bitlbee-configure.XXXXXX)
    506         ret=1
    507         # since we aren't actually linking with ns_* routines
    508         # we can just compile the test code
    509         echo "$RESOLV_NS_TYPES_TESTCODE" | $CC -o $TMPFILE -x c -  >/dev/null 2>/dev/null
    510         if [ "$?" = "0" ]; then
    511                 ret=0
    512         fi
    513 
    514         rm -f $TMPFILE
    515         return $ret
     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
    516490}
    517491
     
    574548if detect_resolv_dynamic || detect_resolv_static; then
    575549        echo '#define HAVE_RESOLV_A' >> config.h
    576         if detect_resolv_ns_dynamic || detect_resolv_ns_static; then
    577                 echo '#define HAVE_RESOLV_A_WITH_NS' >> config.h
    578         fi
    579 else
    580         echo 'Insufficient resolv routines. Jabber server must be set explicitly'
     550    if detect_resolv_ns_dynamic || detect_resolv_ns_static; then
     551            echo '#define HAVE_RESOLV_A_WITH_NS' >> config.h
     552    fi
     553else
     554    echo 'Insufficient resolv routines. Jabber server must be set explicitly'
    581555fi
    582556
     
    675649fi
    676650
    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.'
     651if [ ! -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.'
     655fi
     656
     657REAL_BITLBEE_VERSION=`grep '^#define BITLBEE_VERSION ' $srcdir/bitlbee.h | sed 's/.*\"\(.*\)\".*/\1/'`
     658echo
     659if [ -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"
    685663        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
     669fi
     670
     671if [ -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
     675fi
     676
     677if [ -n "$BITLBEE_VERSION" ]; then
    703678        echo 'Spoofing version number: '$BITLBEE_VERSION
    704679        echo '#undef BITLBEE_VERSION' >> config.h
    705680        echo '#define BITLBEE_VERSION "'$BITLBEE_VERSION'"' >> config.h
    706681        echo
     682else
     683        # for pkg-config
     684        BITLBEE_VERSION=$REAL_BITLBEE_VERSION
    707685fi
    708686
  • doc/CHANGES

    rb1dc403 r531eabd  
    11This 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
     2found in the bzr commit logs, for example you can try:
     3
     4http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on
    485
    496Version 3.2.2:
  • doc/user-guide/commands.xml

    rb1dc403 r531eabd  
    121121                        <description>
    122122                                <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.
    124124                                </para>
    125125
     
    853853                                <varlistentry><term>favourite &lt;screenname|#id&gt;</term><listitem><para>Favo<emphasis>u</emphasis>rite the given user's most recent tweet, or the given tweet ID.</para></listitem></varlistentry>
    854854                                <varlistentry><term>post &lt;message&gt;</term><listitem><para>Post a tweet</para></listitem></varlistentry>
    855                                 <varlistentry><term>url &lt;screenname|#id&gt;</term><listitem><para>Show URL for a tweet to open it in a browser (and see context)</para></listitem></varlistentry>
    856855                        </variablelist>
    857856
  • doc/user-guide/misc.xml

    rb1dc403 r531eabd  
    409409</sect1>
    410410
    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 
    435411</chapter>
  • help.c

    rb1dc403 r531eabd  
    3030#undef write
    3131
    32 #define BUFSIZE 2048
     32#define BUFSIZE 1100
    3333
    3434help_t *help_init(help_t **help, const char *helpfile)
  • ipc.c

    rb1dc403 r531eabd  
    776776        }
    777777
    778         child_list = g_slist_remove(child_list, c);
    779 
    780778        g_free(c->host);
    781779        g_free(c->nick);
     
    783781        g_free(c->password);
    784782        g_free(c);
     783
     784        child_list = g_slist_remove(child_list, c);
    785785
    786786        /* Also, if any child has a reference to this one, remove it. */
  • irc.c

    rb1dc403 r531eabd  
    764764                        irc_rootmsg(irc,
    765765                                    "Welcome to the BitlBee gateway!\n\n"
    766                                     "Running %s %s\n\n"
    767766                                    "If you've never used BitlBee before, please do read the help "
    768767                                    "information using the \x02help\x02 command. Lots of FAQs are "
    769768                                    "answered there.\n"
    770769                                    "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.");
    773771
    774772                        /* This is for bug #209 (use PASS to identify to NickServ). */
  • irc.h

    rb1dc403 r531eabd  
    299299void irc_channel_name_strip(char *name);
    300300int 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);
    303301void irc_channel_update_ops(irc_channel_t *ic, char *value);
    304302char *set_eval_irc_channel_ops(struct set *set, char *value);
  • irc_channel.c

    rb1dc403 r531eabd  
    556556}
    557557
    558 gboolean irc_channel_is_unused(irc_t *irc, char *name)
    559 {
    560         char *type, *chat_type;
    561         irc_channel_t *oic;
    562 
    563         if (!irc_channel_name_ok(name)) {
    564                 return FALSE;
    565         }
    566 
    567         if (!(oic = irc_channel_by_name(irc, name))) {
    568                 return TRUE;
    569         }
    570 
    571         type = set_getstr(&oic->set, "type");
    572         chat_type = set_getstr(&oic->set, "chat_type");
    573 
    574         if (type && chat_type && oic->data == FALSE &&
    575             strcmp(type, "chat") == 0 &&
    576             strcmp(chat_type, "groupchat") == 0) {
    577                 /* There's a channel with this name already, but it looks
    578                    like it's not in use yet. Most likely the IRC client
    579                    rejoined the channel after a reconnect. Remove it so
    580                    we can reuse its name. */
    581                 irc_channel_free(oic);
    582                 return TRUE;
    583         }
    584 
    585         return FALSE;
    586 }
    587 
    588 char *irc_channel_name_gen(irc_t *irc, const char *hint)
    589 {
    590         char name[MAX_NICK_LENGTH + 1] = { 0 };
    591         char *translit_name;
    592         gsize bytes_written;
    593 
    594         translit_name = g_convert_with_fallback(hint, -1, "ASCII//TRANSLIT", "UTF-8", "", NULL, &bytes_written, NULL);
    595         if (bytes_written > MAX_NICK_LENGTH) {
    596                 translit_name[MAX_NICK_LENGTH] = '\0';
    597         }
    598 
    599         name[0] = '#';
    600         strncpy(name + 1, translit_name, MAX_NICK_LENGTH - 1);
    601         name[MAX_NICK_LENGTH] = '\0';
    602 
    603         g_free(translit_name);
    604 
    605         irc_channel_name_strip(name);
    606 
    607         if (set_getbool(&irc->b->set, "lcnicks")) {
    608                 nick_lc(irc, name + 1);
    609         }
    610 
    611         while (!irc_channel_is_unused(irc, name)) {
    612                 underscore_dedupe(name);
    613         }
    614 
    615         return g_strdup(name);
    616 }
    617 
    618 gboolean irc_channel_name_hint(irc_channel_t *ic, const char *name)
    619 {
    620         irc_t *irc = ic->irc;
    621         char *full_name;
    622 
    623         /* Don't rename a channel if the user's in it already. */
    624         if (ic->flags & IRC_CHANNEL_JOINED) {
    625                 return FALSE;
    626         }
    627 
    628         if (!(full_name = irc_channel_name_gen(irc, name))) {
    629                 return FALSE;
    630         }
    631 
    632         g_free(ic->name);
    633         ic->name = full_name;
    634 
    635         return TRUE;
    636 }
    637 
    638558static gint irc_channel_user_cmp(gconstpointer a_, gconstpointer b_)
    639559{
  • irc_im.c

    rb1dc403 r531eabd  
    235235                        } else {
    236236                                /* Modules can swallow messages. */
    237                                 goto cleanup;
     237                                return TRUE;
    238238                        }
    239239                }
     
    250250        wrapped = word_wrap(msg, 425);
    251251        irc_send_msg(iu, "PRIVMSG", dst, wrapped, prefix);
     252
    252253        g_free(wrapped);
    253 
    254 cleanup:
    255254        g_free(prefix);
    256255        g_free(msg);
     
    292291
    293292        irc_send_msg((irc_user_t *) bu->ui_data, "NOTICE", irc->user->nick, msg->str, NULL);
    294 
    295         g_string_free(msg, TRUE);
    296293
    297294        return TRUE;
     
    696693static gboolean bee_irc_chat_name_hint(bee_t *bee, struct groupchat *c, const char *name)
    697694{
    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;
    699744}
    700745
  • irc_send.c

    rb1dc403 r531eabd  
    5555{
    5656        char motd[2048];
    57         ssize_t len;
     57        size_t len;
    5858        int fd;
    5959
  • lib/misc.c

    rb1dc403 r531eabd  
    719719                        }
    720720
     721                        /* Make sure we're still inside the string */
     722                        if (i >= len) {
     723                                return(NULL);
     724                        }
     725
    721726                        /* Copy the found data */
    722727                        return(g_strndup(ret, text + i - ret));
  • lib/oauth.c

    rb1dc403 r531eabd  
    9898        GSList *l, *n;
    9999
    100         if (!params) {
     100        if (params == NULL) {
    101101                return;
    102102        }
     
    104104        for (l = *params; l; l = n) {
    105105                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);
    111111                }
    112112        }
  • lib/proxy.c

    rb1dc403 r531eabd  
    6363static int proxy_connect_none(const char *host, unsigned short port_, struct PHB *phb);
    6464
    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)
     65static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition cond)
    7566{
    7667        struct PHB *phb = data;
     
    8980                                dup2(new_fd, source);
    9081                                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);
    9283                                return FALSE;
    9384                        }
    9485                }
     86                freeaddrinfo(phb->gai);
    9587                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        }
    10298        freeaddrinfo(phb->gai);
     99        sock_make_blocking(source);
    103100        b_event_remove(phb->inpa);
    104101        phb->inpa = 0;
     
    163160                        continue;
    164161                } 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);
    166163                        phb->fd = fd;
    167164
     
    209206        }
    210207
    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;
    212214}
    213215
     
    224226        len = sizeof(error);
    225227        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;
    227233        }
    228234        sock_make_blocking(source);
     
    231237                   phb->host, phb->port);
    232238        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;
    234244        }
    235245
     
    242252                g_free(t2);
    243253                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;
    245259                }
    246260        }
     
    248262        g_snprintf(cmd, sizeof(cmd), "\r\n");
    249263        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;
    251269        }
    252270
     
    284302        }
    285303
    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;
    287310}
    288311
     
    300323        len = sizeof(error);
    301324        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;
    303330        }
    304331        sock_make_blocking(source);
     
    306333        /* XXX does socks4 not support host name lookups by the proxy? */
    307334        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;
    309340        }
    310341
     
    319350        packet[8] = 0;
    320351        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;
    322357        }
    323358
     
    348383
    349384        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;
    351390        }
    352391        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;
    354397        }
    355398
     
    377420
    378421        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);
    380426                return;
    381427        }
     
    392438
    393439        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;
    395445        }
    396446
    397447        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;
    399453        }
    400454
     
    412466
    413467        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;
    415473        }
    416474
    417475        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;
    419481        }
    420482
     
    427489                memcpy(buf + 2 + i + 1, proxypass, j);
    428490                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;
    430496                }
    431497
     
    451517        len = sizeof(error);
    452518        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;
    454524        }
    455525        sock_make_blocking(source);
     
    469539
    470540        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;
    472546        }
    473547
  • lib/ssl_gnutls.c

    rb1dc403 r531eabd  
    124124
    125125        if (conn->fd < 0) {
    126                 g_free(conn->hostname);
    127126                g_free(conn);
    128127                return NULL;
     
    315314        if (source == -1) {
    316315                conn->func(conn->data, 0, NULL, cond);
    317                 g_free(conn->hostname);
    318316                g_free(conn);
    319317                return FALSE;
     
    357355                        conn->func(conn->data, 0, NULL, cond);
    358356
    359                         ssl_disconnect(conn);
     357                        gnutls_deinit(conn->session);
     358                        closesocket(conn->fd);
     359
     360                        g_free(conn);
    360361                }
    361362        } else {
     
    363364                        conn->func(conn->data, stver, NULL, cond);
    364365
    365                         ssl_disconnect(conn);
     366                        gnutls_deinit(conn->session);
     367                        closesocket(conn->fd);
     368
     369                        g_free(conn);
    366370                } else {
    367371                        /* For now we can't handle non-blocking perfectly everywhere... */
  • nick.c

    rb1dc403 r531eabd  
    214214}
    215215
    216 /* Used for nicks and channel names too! */
    217 void underscore_dedupe(char nick[MAX_NICK_LENGTH + 1])
    218 {
    219         if (strlen(nick) < (MAX_NICK_LENGTH - 1)) {
    220                 nick[strlen(nick) + 1] = 0;
    221                 nick[strlen(nick)] = '_';
    222         } else {
    223                 /* We've got no more space for underscores,
    224                    so truncate it and replace the last three
    225                    chars with a random "_XX" suffix */
    226                 int len = truncate_utf8(nick, MAX_NICK_LENGTH - 3);
    227                 nick[len] = '_';
    228                 g_snprintf(nick + len + 1, 3, "%2x", rand());
    229         }
    230 }
    231 
    232216void nick_dedupe(bee_user_t *bu, char nick[MAX_NICK_LENGTH + 1])
    233217{
     
    240224        while (!nick_ok(irc, nick) ||
    241225               ((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                }
    244237
    245238                if (inf_protection-- == 0) {
  • nick.h

    rb1dc403 r531eabd  
    2828char *nick_get(bee_user_t *bu);
    2929char *nick_gen(bee_user_t *bu);
    30 void underscore_dedupe(char nick[MAX_NICK_LENGTH + 1]);
    3130void nick_dedupe(bee_user_t * bu, char nick[MAX_NICK_LENGTH + 1]);
    3231int nick_saved(bee_user_t *bu);
  • otr.c

    rb1dc403 r531eabd  
    287287void otr_irc_free(irc_t *irc)
    288288{
    289         set_t *s;
    290289        otr_t *otr = irc->otr;
    291290
     
    293292        b_event_remove(otr->timer);
    294293        otrl_userstate_free(otr->us);
    295 
    296         s = set_find(&irc->b->set, "otr_policy");
    297         g_slist_free(s->eval_data);
    298 
    299294        if (otr->keygen) {
    300295                kill(otr->keygen, SIGTERM);
     
    439434                                            ic->acc->user, ic->acc->prpl->name, iu->bu->handle, msg, &newmsg,
    440435                                            &tlvs, NULL, NULL, NULL);
    441 
    442         if (tlvs) {
    443                 otrl_tlv_free(tlvs);
    444         }
    445436
    446437        if (ignore_msg) {
     
    481472                /* libotr wants us to replace our message */
    482473                /* NB: caller will free old msg */
    483                 msg = st ? NULL : g_strdup(otrmsg);
     474                msg = g_strdup(otrmsg);
    484475                otrl_message_free(otrmsg);
    485476        }
     
    13341325
    13351326        log_message(LOGLVL_INFO, "otr: %s", msg);
    1336 
    1337         g_free(msg);
    13381327}
    13391328
     
    20862075        }
    20872076}
     2077
     2078/* vim: set noet ts=4 sw=4: */
  • protocols/bee.h

    rb1dc403 r531eabd  
    154154G_MODULE_EXPORT void imcb_buddy_times(struct im_connection *ic, const char *handle, time_t login, time_t idle);
    155155/* 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, const char *msg, guint32 flags,
     156G_MODULE_EXPORT void imcb_buddy_msg(struct im_connection *ic, const char *handle, char *msg, guint32 flags,
    157157                                    time_t sent_at);
    158158
  • protocols/bee_user.c

    rb1dc403 r531eabd  
    6868        }
    6969
    70         bee->users = g_slist_remove(bee->users, bu);
    71 
    7270        g_free(bu->handle);
    7371        g_free(bu->fullname);
     
    7674        g_free(bu->status_msg);
    7775        g_free(bu);
     76
     77        bee->users = g_slist_remove(bee->users, bu);
    7878
    7979        return 1;
     
    247247}
    248248
    249 void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, uint32_t flags, time_t sent_at)
     249void imcb_buddy_msg(struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at)
    250250{
    251251        bee_t *bee = ic->bee;
  • protocols/jabber/Makefile

    rb1dc403 r531eabd  
    1313
    1414# [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.o
     15objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o s5bytestream.o sasl.o si.o
    1616
    1717LFLAGS += -r
  • protocols/jabber/conference.c

    rb1dc403 r531eabd  
    359359
    360360        if (subject && chat) {
    361                 s = (bud && bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL;
     361                s = bud ? strchr(bud->ext_jid, '/') : NULL;
    362362                if (s) {
    363363                        *s = 0;
     
    419419        }
    420420        if (body && body->text_len > 0) {
    421                 s = (bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL;
     421                s = strchr(bud->ext_jid, '/');
    422422                if (s) {
    423423                        *s = 0;
  • protocols/jabber/iq.c

    rb1dc403 r531eabd  
    2727static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
    2828static xt_status jabber_iq_display_vcard(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
     29static int jabber_iq_disco_server(struct im_connection *ic);
    2930
    3031xt_status jabber_pkt_iq(struct xt_node *node, gpointer data)
     
    373374static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
    374375{
    375         struct jabber_data *jd = ic->proto_data;
    376376        struct xt_node *query, *c;
    377377        int initial = (orig != NULL);
     
    388388                char *name = xt_find_attr(c, "name");
    389389                char *sub = xt_find_attr(c, "subscription");
    390                 char *mention_name = xt_find_attr(c, "mention_name");
    391390
    392391                if (jid && sub) {
     
    397396                                if (name) {
    398397                                        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);
    405398                                }
    406399                        } else if (strcmp(sub, "remove") == 0) {
     
    862855                                                 struct xt_node *node, struct xt_node *orig);
    863856
    864 int jabber_iq_disco_server(struct im_connection *ic)
     857static int jabber_iq_disco_server(struct im_connection *ic)
    865858{
    866859        struct xt_node *node, *iq;
  • protocols/jabber/jabber.c

    rb1dc403 r531eabd  
    6161        s = set_add(&acc->set, "activity_timeout", "600", set_eval_int, acc);
    6262
     63        s = set_add(&acc->set, "oauth", "false", set_eval_oauth, acc);
     64
    6365        s = set_add(&acc->set, "display_name", NULL, NULL, acc);
    6466
     
    8183        s = set_add(&acc->set, "server", NULL, set_eval_account, acc);
    8284        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         }
    8985
    9086        s = set_add(&acc->set, "ssl", "false", set_eval_bool, acc);
     
    125121
    126122        jd->fd = jd->r_inpa = jd->w_inpa = -1;
    127 
    128         if (strcmp(acc->prpl->name, "hipchat") == 0) {
    129                 jd->flags |= JFLAG_HIPCHAT;
    130         }
    131123
    132124        if (jd->server == NULL) {
     
    664656{
    665657        struct prpl *ret = g_new0(struct prpl, 1);
    666         struct prpl *hipchat = NULL;
    667658
    668659        ret->name = "jabber";
     
    695686
    696687        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  
    4848
    4949        JFLAG_GTALK =  0x100000,        /* Is Google Talk, as confirmed by iq discovery */
    50         JFLAG_HIPCHAT = 0x200000,       /* Is hipchat, because prpl->name says so */
    5150
    5251        JFLAG_SASL_FB = 0x10000,        /* Trying Facebook authentication. */
     
    236235#define XMLNS_IBB          "http://jabber.org/protocol/ibb"                      /* XEP-0047 */
    237236
    238 /* Hipchat protocol extensions*/
    239 #define XMLNS_HIPCHAT         "http://hipchat.com"
    240 #define XMLNS_HIPCHAT_PROFILE "http://hipchat.com/protocol/profile"
    241 
    242237/* jabber.c */
    243238void jabber_connect(struct im_connection *ic);
     
    254249xt_status jabber_iq_query_server(struct im_connection *ic, char *jid, char *xmlns);
    255250void jabber_iq_version_send(struct im_connection *ic, struct jabber_buddy *bud, void *data);
    256 int jabber_iq_disco_server(struct im_connection *ic);
    257251
    258252/* si.c */
     
    347341void jabber_chat_invite(struct groupchat *c, char *who, char *message);
    348342
    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 
    354343#endif
  • protocols/jabber/jabber_util.c

    rb1dc403 r531eabd  
    566566
    567567        if ((s = strchr(jid, '=')) == NULL) {
    568                 g_free(jid);
    569568                return NULL;
    570569        }
  • protocols/jabber/s5bytestream.c

    rb1dc403 r531eabd  
    2323
    2424#include "jabber.h"
     25#include "sha1.h"
    2526#include "lib/ftutil.h"
    2627#include <poll.h>
     
    4142
    4243        /* SHA1( SID + Initiator JID + Target JID) */
    43         char *pseudoaddr;
     44        char *pseudoadr;
    4445
    4546        gint connect_timeout;
     
    129130        }
    130131
    131         g_free(bt->pseudoaddr);
     132        g_free(bt->pseudoadr);
    132133
    133134        while (bt->streamhosts) {
     
    253254}
    254255
    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 
    280256/* Bad luck */
    281257void jabber_bs_canceled(file_transfer_t *ft, char *reason)
     
    284260
    285261        imcb_log(tf->ic, "File transfer aborted: %s", reason);
    286 }
    287 
    288 static struct jabber_transfer *get_ft_by_sid(GSList *tflist, char *sid) {
    289         GSList *l;
    290         for (l = tflist; l; l = g_slist_next(l)) {
    291                 struct jabber_transfer *tft = l->data;
    292                 if ((strcmp(tft->sid, sid) == 0)) {
    293                         return tft;
    294                 }
    295         }
    296         return NULL;
    297 }
    298 
    299 /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value
    300  * Returns a newly allocated string */
    301 static char *generate_pseudoaddr(char *sid, char *ini_jid, char *tgt_jid) {
    302         char *contents = g_strconcat(sid, ini_jid, tgt_jid, NULL);
    303         char *hash_hex = g_compute_checksum_for_string(G_CHECKSUM_SHA1, contents, -1);
    304         g_free(contents);
    305         return hash_hex;
    306 }
    307 
    308 static jabber_streamhost_t *jabber_streamhost_new(char *jid, char *host, int port)
    309 {
    310         jabber_streamhost_t *sh = g_new0(jabber_streamhost_t, 1);
    311         sh->jid = g_strdup(jid);
    312         sh->host = g_strdup(host);
    313         if (port) {
    314                 g_snprintf(sh->port, sizeof(sh->port), "%u", port);
    315         }
    316         return sh;
    317262}
    318263
     
    325270        struct jabber_data *jd = ic->proto_data;
    326271        struct jabber_transfer *tf = NULL;
     272        GSList *tflist;
    327273        struct bs_transfer *bt;
    328274        GSList *shlist = NULL;
    329275        struct xt_node *shnode;
     276
     277        sha1_state_t sha;
     278        char hash_hex[41];
     279        unsigned char hash[20];
     280        int i;
    330281
    331282        if (!(iq_id   = xt_find_attr(node, "id")) ||
     
    352303                    (port_s = xt_find_attr(shnode, "port")) &&
    353304                    (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);
    355310                }
    356311                shnode = shnode->next;
     
    362317        }
    363318
    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) {
    365332                imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid);
    366333                return XT_HANDLED;
     
    372339
    373340        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        }
    374352
    375353        bt = g_new0(struct bs_transfer, 1);
     
    378356        bt->sh = shlist->data;
    379357        bt->phase = BS_PHASE_CONNECT;
    380         bt->pseudoaddr = generate_pseudoaddr(sid, ini_jid, tgt_jid);
     358        bt->pseudoadr = g_strdup(hash_hex);
    381359        tf->streamhandle = bt;
    382360        tf->ft->free = jabber_bs_free_transfer;
     
    473451                        .rsv = 0,
    474452                        .atyp = 0x03,
    475                         .addrlen = strlen(bt->pseudoaddr),
     453                        .addrlen = strlen(bt->pseudoadr),
    476454                        .port = 0
    477455                };
     
    490468
    491469                /* copy hash into connect message */
    492                 memcpy(socks5_connect.address, bt->pseudoaddr, socks5_connect.addrlen);
     470                memcpy(socks5_connect.address, bt->pseudoadr, socks5_connect.addrlen);
    493471
    494472                ASSERTSOCKOP(send(fd, &socks5_connect, sizeof(struct socks5_message), 0), "Sending SOCKS5 Connect");
     
    580558        if (shlist && shlist->next) {
    581559                bt->sh = shlist->next->data;
    582                 jabber_bs_remove_events(bt);
    583560                return jabber_bs_recv_handshake(bt, -1, 0);
    584561        }
     
    754731        struct jabber_data *jd = ic->proto_data;
    755732        struct bs_transfer *bt;
     733        GSList *tflist;
    756734        struct xt_node *c;
    757735        char *sid, *jid;
     
    772750        /* Let's see if we can find out what this bytestream should be for... */
    773751
    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) {
    775761                imcb_log(ic, "WARNING: Received SOCKS5 bytestream reply to unknown request");
    776762                return XT_HANDLED;
     
    790776                /* using a proxy, abort listen */
    791777
    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                }
    793792
    794793                GSList *shlist;
     
    839838{
    840839        char *sid;
     840        GSList *tflist;
    841841        struct jabber_transfer *tf = NULL;
    842842        struct xt_node *query;
     
    846846        sid = xt_find_attr(query, "sid");
    847847
    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) {
    849857                imcb_log(ic, "WARNING: Received SOCKS5 bytestream activation for unknown stream");
    850858                return XT_HANDLED;
     
    875883        *port++ = '\0';
    876884
    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);
    879889
    880890        return sh;
     
    900910                if (strcmp(proxy, "<local>") == 0) {
    901911                        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);
    904916                                bt->streamhosts = g_slist_append(bt->streamhosts, sh);
    905917
     
    936948{
    937949        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        }
    938965
    939966        bt = g_new0(struct bs_transfer, 1);
    940967        bt->tf = tf;
    941968        bt->phase = BS_PHASE_CONNECT;
    942         bt->pseudoaddr = generate_pseudoaddr(tf->sid, tf->ini_jid, tf->tgt_jid);
     969        bt->pseudoadr = g_strdup(hash_hex);
    943970        tf->streamhandle = bt;
    944971        tf->ft->free = jabber_bs_free_transfer;
     
    947974        jabber_si_set_proxies(bt);
    948975
    949         return jabber_bs_send_request(tf, bt->streamhosts);
     976        ret = jabber_bs_send_request(tf, bt->streamhosts);
     977
     978        return ret;
    950979}
    951980
     
    11101139                                               socks5_connect.atyp);
    11111140                }
    1112                 if (!(memcmp(socks5_connect.address, bt->pseudoaddr, 40) == 0)) {
     1141                if (!(memcmp(socks5_connect.address, bt->pseudoadr, 40) == 0)) {
    11131142                        return jabber_bs_abort(bt, "SOCKS5 Connect message contained wrong digest");
    11141143                }
  • protocols/jabber/sasl.c

    rb1dc403 r531eabd  
    4242        "https://www.facebook.com/dialog/oauth",
    4343        "https://graph.facebook.com/oauth/access_token",
    44         "https://www.bitlbee.org/main.php/Facebook/oauth2.html",
     44        "http://www.bitlbee.org/main.php/Facebook/oauth2.html",
    4545        "offline_access,xmpp_login",
    4646        "126828914005625",
     
    5555        char *s;
    5656        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;
    5858        GString *mechs;
    5959
     
    7575
    7676        want_oauth = set_getbool(&ic->acc->set, "oauth");
    77         want_hipchat = (jd->flags & JFLAG_HIPCHAT);
    7877
    7978        mechs = g_string_new("");
     
    112111
    113112        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);
    119114
    120115        if (sup_gtalk && want_oauth) {
     
    148143        } else if (sup_plain) {
    149144                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");
    162147
    163148                /* 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);
    177154                reply->text = base64_encode((unsigned char *) s, len);
    178155                reply->text_len = strlen(reply->text);
     
    420397                imcb_log(ic, "Authentication finished");
    421398                jd->flags |= JFLAG_AUTHENTICATED | JFLAG_STREAM_RESTART;
    422 
    423                 if (jd->flags & JFLAG_HIPCHAT) {
    424                         return hipchat_handle_success(ic, node);
    425                 }
    426399        } else if (strcmp(node->name, "failure") == 0) {
    427400                imcb_error(ic, "Authentication failure");
  • protocols/msn/Makefile

    rb1dc403 r531eabd  
    1313
    1414# [SH] Program variables
    15 objects = msn.o msn_util.o ns.o soap.o tables.o gw.o
     15objects = msn.o msn_util.o ns.o sb.o soap.o tables.o
    1616
    1717LFLAGS += -r
  • protocols/msn/msn.c

    rb1dc403 r531eabd  
    3030int msn_chat_id;
    3131GSList *msn_connections;
     32GSList *msn_switchboards;
    3233
    3334static char *set_eval_display_name(set_t *set, char *value);
     
    4041        s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;
    4142
    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);
    4344        s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
    4445
     
    4748
    4849        set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
     50        set_add(&acc->set, "switchboard_keepalives", "false", set_eval_bool, acc);
    4951
    5052        acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE |
     
    5658        struct im_connection *ic = imcb_new(acc);
    5759        struct msn_data *md = g_new0(struct msn_data, 1);
    58         char *server = set_getstr(&ic->acc->set, "server");
    5960
    6061        ic->proto_data = md;
    6162        ic->flags |= OPT_PONGS | OPT_PONGED;
    62 
    63         if (!server) {
    64                 server = "geo.gateway.messenger.live.com";
    65         }
    6663
    6764        if (strchr(acc->user, '@') == NULL) {
     
    7471        md->away_state = msn_away_state_list;
    7572        md->domaintree = g_tree_new(msn_domaintree_cmp);
    76         md->fd = -1;
    77         md->is_http = TRUE;
     73        md->ns->fd = -1;
    7874
    7975        msn_connections = g_slist_prepend(msn_connections, ic);
    8076
    8177        imcb_log(ic, "Connecting");
    82         msn_ns_connect(ic, server,
     78        msn_ns_connect(ic, md->ns,
     79                       set_getstr(&ic->acc->set, "server"),
    8380                       set_getint(&ic->acc->set, "port"));
    8481}
     
    9188
    9289        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);
    95103                msn_soapq_flush(ic, FALSE);
    96104
     
    104112                while (md->groups) {
    105113                        struct msn_group *mg = md->groups->data;
    106                         md->groups = g_slist_remove(md->groups, mg);
    107114                        g_free(mg->id);
    108115                        g_free(mg->name);
    109116                        g_free(mg);
     117                        md->groups = g_slist_remove(md->groups, mg);
    110118                }
    111119
     
    119127                while (md->grpq) {
    120128                        struct msn_groupadd *ga = md->grpq->data;
    121                         md->grpq = g_slist_remove(md->grpq, ga);
    122129                        g_free(ga->group);
    123130                        g_free(ga->who);
    124131                        g_free(ga);
     132                        md->grpq = g_slist_remove(md->grpq, ga);
    125133                }
    126134
     
    144152{
    145153        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;
    146156
    147157#ifdef DEBUG
    148158        if (strcmp(who, "raw") == 0) {
    149159                msn_ns_write(ic, -1, "%s\r\n", message);
    150                 return 0;
    151         }
     160        } else
    152161#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
    155177        return(0);
    156178}
     
    174196static void msn_set_away(struct im_connection *ic, char *state, char *message)
    175197{
     198        char *uux;
    176199        struct msn_data *md = ic->proto_data;
    177         char *nick, *psm, *idle, *statecode, *body, *buf;
    178200
    179201        if (state == NULL) {
     
    183205        }
    184206
    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);
    202233}
    203234
     
    225256static void msn_chat_msg(struct groupchat *c, char *message, int flags)
    226257{
    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! */
    228265}
    229266
    230267static void msn_chat_invite(struct groupchat *c, char *who, char *message)
    231268{
    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        }
    233274}
    234275
    235276static void msn_chat_leave(struct groupchat *c)
    236277{
    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        }
    238283}
    239284
    240285static struct groupchat *msn_chat_with(struct im_connection *ic, char *who)
    241286{
    242         /* TODO: groupchats*/
     287        struct msn_switchboard *sb;
    243288        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        }
    245305}
    246306
     
    262322static void msn_add_deny(struct im_connection *ic, char *who)
    263323{
     324        struct msn_switchboard *sb;
     325
    264326        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        }
    265332}
    266333
     
    395462        ret->buddy_action = msn_buddy_action;
    396463
     464        //ret->transfer_request = msn_ftp_transfer_request;
     465
    397466        register_protocol(ret);
    398467}
  • protocols/msn/msn.h

    rb1dc403 r531eabd  
    3232#define NUDGE_MESSAGE "\r\r\rSHAKE THAT THING\r\r\r"
    3333#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"
    3435
    3536#ifdef DEBUG_MSN
     
    5960#define MSNP11_PROD_KEY "C1BX{V4W}Q3*10SM"
    6061#define MSNP11_PROD_ID  "PROD0120PW!CCV9@"
    61 #define MSNP_VER        "MSNP21"
     62#define MSNP_VER        "MSNP18"
    6263#define MSNP_BUILD      "14.0.8117.416"
    6364
     
    6768#define MSN_CAP2        0x0000
    6869
    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" \
    7574        "\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>"
    10475
    10576#define MSN_TYPING_HEADERS "MIME-Version: 1.0\r\n" \
     
    11384        "ID: 1\r\n" \
    11485        "\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"
    11590
    11691#define PROFILE_URL "http://members.msn.com/"
     
    12499} msn_flags_t;
    125100
    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 {
     101struct msn_handler_data {
    149102        int fd, inpa;
    150103        int rxlen;
     
    154107        char *cmd_text;
    155108
     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
     116struct msn_data {
    156117        struct im_connection *ic;
    157118
     119        struct msn_handler_data ns[1];
    158120        msn_flags_t flags;
    159121
     
    164126
    165127        GSList *msgq, *grpq, *soapq;
     128        GSList *switchboards;
     129        int sb_failures;
     130        time_t first_sb_failure;
    166131
    167132        const struct msn_away_state *away_state;
     
    174139        GTree *domaintree;
    175140        int adl_todo;
    176 
    177         gboolean is_http;
    178         struct msn_gw *gw;
     141};
     142
     143struct 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;
    179161};
    180162
     
    223205#define STATUS_FATAL            1
    224206#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). */
    225209
    226210extern int msn_chat_id;
     
    234218   before doing *anything* else. */
    235219extern GSList *msn_connections;
     220extern GSList *msn_switchboards;
    236221
    237222/* ns.c */
    238223int 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);
     224gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port);
     225void msn_ns_close(struct msn_handler_data *handler);
    241226void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error);
    242227void msn_auth_got_contact_list(struct im_connection *ic);
    243228int msn_ns_finish_login(struct im_connection *ic);
    244229int 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);
     230void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq);
    247231
    248232/* msn_util.c */
     
    251235int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group);
    252236void 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);
     237char **msn_linesplit(char *line);
     238int msn_handler(struct msn_handler_data *h);
     239void msn_msgq_purge(struct im_connection *ic, GSList **list);
    255240char *msn_p11_challenge(char *challenge);
    256241gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_);
     
    266251const struct msn_status_code *msn_status_by_number(int number);
    267252
    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 */
     254int msn_sb_write(struct msn_switchboard *sb, const char *fmt, ...) G_GNUC_PRINTF(2, 3);;
     255struct msn_switchboard *msn_sb_create(struct im_connection *ic, char *host, int port, char *key, int session);
     256struct msn_switchboard *msn_sb_by_handle(struct im_connection *ic, const char *handle);
     257struct msn_switchboard *msn_sb_by_chat(struct groupchat *c);
     258struct msn_switchboard *msn_sb_spare(struct im_connection *ic);
     259int msn_sb_sendmessage(struct msn_switchboard *sb, char *text);
     260struct groupchat *msn_sb_to_chat(struct msn_switchboard *sb);
     261void msn_sb_destroy(struct msn_switchboard *sb);
     262gboolean msn_sb_connected(gpointer data, gint source, b_input_condition cond);
     263int msn_sb_write_msg(struct im_connection *ic, struct msn_message *m);
     264void msn_sb_start_keepalives(struct msn_switchboard *sb, gboolean initial);
     265void msn_sb_stop_keepalives(struct msn_switchboard *sb);
    274266
    275267#endif //_MSN_H
  • protocols/msn/msn_util.c

    rb1dc403 r531eabd  
    5555
    5656        *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
    5799
    58100        if (!((bu = bee_user_by_handle(ic->bee, ic, who)) ||
     
    90132
    91133        *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
    92145
    93146        if (!(bu = bee_user_by_handle(ic->bee, ic, who)) ||
     
    121174};
    122175
    123 static void msn_buddy_ask_free(void *data)
     176static void msn_buddy_ask_yes(void *data)
    124177{
    125178        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);
    126183
    127184        g_free(bla->handle);
     
    130187}
    131188
    132 static void msn_buddy_ask_yes(void *data)
     189static void msn_buddy_ask_no(void *data)
    133190{
    134191        struct msn_buddy_ask_data *bla = data;
    135192
    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 
    147193        msn_buddy_list_add(bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL);
    148194
    149         msn_buddy_ask_free(bla);
     195        g_free(bla->handle);
     196        g_free(bla->realname);
     197        g_free(bla);
    150198}
    151199
     
    168216                   "The user %s (%s) wants to add you to his/her buddy list.",
    169217                   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... */
     222char **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);
    185252}
    186253
     
    193260                   1: OK */
    194261
    195 int msn_handler(struct msn_data *h)
    196 {
    197         int st = 1;
     262int 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        }
    198278
    199279        while (st) {
     
    207287
    208288                                        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);
    215294                                        g_free(cmd_text);
    216295
     
    235314                        /* If we reached the end of the buffer, there's still an incomplete command there.
    236315                           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') {
    238317                                break;
    239318                        }
     
    248327
    249328                        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);
    257335                        g_free(msg);
    258336                        g_free(h->cmd_text);
     
    288366}
    289367
     368void 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
    290408/* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */
    291409char *msn_p11_challenge(char *challenge)
     
    411529int msn_ns_set_display_name(struct im_connection *ic, const char *value)
    412530{
    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);
    415540}
    416541
  • protocols/msn/ns.c

    rb1dc403 r531eabd  
    3535static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond);
    3636static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond);
     37static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts);
     38static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts);
    3739
    3840static void msn_ns_send_adl_start(struct im_connection *ic);
    3941static 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);
    4342
    4443int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...)
     
    5554
    5655        if (fd < 0) {
    57                 fd = md->fd;
     56                fd = md->ns->fd;
    5857        }
    5958
    6059        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);
    6261        }
    6362
    6463        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);
    7365        g_free(out);
    7466        if (st != len) {
     
    8173}
    8274
    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) {
     75gboolean 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) {
    11386                imcb_error(ic, "Could not connect to server");
    11487                imc_logout(ic, TRUE);
     
    11689        }
    11790
    118         g_free(md->rxq);
    119         md->rxlen = 0;
    120         md->rxq = g_new0(char, 1);
     91        return TRUE;
     92}
     93
     94static 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);
    121115
    122116        if (md->uuid == NULL) {
     
    136130
    137131        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);
    141133                imcb_log(ic, "Connected to server, waiting for reply");
    142134        }
     
    145137}
    146138
    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;
     139void 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;
    164153}
    165154
    166155static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond)
    167156{
    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. */
    181161                imcb_error(ic, "Error while reading from server");
    182162                imc_logout(ic, TRUE);
     163
    183164                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
     170static 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;
    200174
    201175        if (num_parts == 0) {
     
    211185                }
    212186
    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",
    214188                                    ++md->trId, ic->acc->user));
    215189        } else if (strcmp(cmd[0], "CVR") == 0) {
    216190                /* 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);
    218192        } else if (strcmp(cmd[0], "XFR") == 0) {
    219193                char *server;
     
    221195
    222196                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;
    225199
    226200                        server = strchr(cmd[3], ':');
     
    235209
    236210                        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                        }
    238259                } else {
    239260                        imcb_error(ic, "Syntax error");
     
    269290                }
    270291
    271                 md->msglen = atoi(cmd[3]);
    272 
    273                 if (md->msglen <= 0) {
     292                handler->msglen = atoi(cmd[3]);
     293
     294                if (handler->msglen <= 0) {
    274295                        imcb_error(ic, "Syntax error");
    275296                        imc_logout(ic, TRUE);
    276297                        return(0);
    277298                }
     299        } else if (strcmp(cmd[0], "BLP") == 0) {
     300                msn_ns_send_adl_start(ic);
     301                return msn_ns_finish_login(ic);
    278302        } else if (strcmp(cmd[0], "ADL") == 0) {
    279303                if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) {
     
    281305                        return msn_ns_finish_login(ic);
    282306                } 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);
    285311        } else if (strcmp(cmd[0], "CHL") == 0) {
    286312                char *resp;
     
    300326                g_free(resp);
    301327                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                }
    304417        } 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);
    307431                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) {
    309485                /* Coming up is cmd[2] bytes of stuff we're supposed to
    310486                   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. */
    313490                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]);
    319492                }
    320493        } else if (strcmp(cmd[0], "NOT") == 0) {
     494                /* Some kind of notification, poorly documented but
     495                   apparently used to announce address book changes. */
    321496                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]);
    323502                }
    324503        } else if (strcmp(cmd[0], "QNG") == 0) {
     
    337516                /* Oh yes, errors can have payloads too now. Discard them for now. */
    338517                if (num_parts >= 3) {
    339                         md->msglen = atoi(cmd[2]);
     518                        handler->msglen = atoi(cmd[2]);
    340519                }
    341520        } 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] ); */
    343522        }
    344523
     
    346525}
    347526
    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;
     527static 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;
    351530        char *body;
    352531        int blen = 0;
     
    419598                                }
    420599                        } 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);
    422652                        } else {
    423653                                debug("Can't handle %s packet from notification server", ct);
     
    426656                        g_free(ct);
    427657                }
     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);
    428670        } else if (strcmp(cmd[0], "ADL") == 0) {
    429671                struct xt_node *adl, *d, *c;
     
    474716                        }
    475717                }
    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);
    478744        }
    479745
    480746        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);
    586747}
    587748
     
    607768void msn_auth_got_contact_list(struct im_connection *ic)
    608769{
     770        struct msn_data *md;
     771
    609772        /* Dead connection? */
    610773        if (g_slist_find(msn_connections, ic) == NULL) {
     
    612775        }
    613776
    614         msn_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");
    616779}
    617780
    618781static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data)
    619782{
    620         struct xt_node *adl = data, *d, *c, *s;
     783        struct xt_node *adl = data, *d, *c;
    621784        struct bee_user *bu = value;
    622785        struct msn_buddy_data *bd = bu->data;
     
    647810        c = xt_new_node("c", NULL, NULL);
    648811        xt_add_attr(c, "n", handle);
     812        xt_add_attr(c, "l", l);
    649813        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);
    654814        xt_insert_child(d, c);
    655815
     
    721881
    722882        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                }
    724888        }
    725889
     
    727891}
    728892
    729 // TODO: typing notifications, nudges lol, etc
    730893int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text)
    731894{
    732895        struct msn_data *md = ic->proto_data;
    733         int retval = 0;
    734         char *buf;
     896        int type = 0;
     897        char *buf, *handle;
    735898
    736899        if (strncmp(text, "\r\r\r", 3) == 0) {
     
    740903        }
    741904
    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
     928void 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  
    209209                return;
    210210        }
    211         fprintf(stderr, "\n\x1b[90mSOAP:\n");
    212211
    213212        if (headers) {
     
    226225                xt_free_node(xt);
    227226        }
    228         fprintf(stderr, "\n\x1b[97m\n");
    229227}
    230228
  • protocols/msn/soap.h

    rb1dc403 r531eabd  
    167167
    168168#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>" \
    170170        "</FindMembership>"
    171171
  • protocols/msn/tables.c

    rb1dc403 r531eabd  
    7373        { 206, "Domain name missing",                                   0 },
    7474        { 207, "Already logged in",                                     0 },
    75         { 208, "Invalid handle",                                        0 },
     75        { 208, "Invalid handle",                                        STATUS_SB_IM_SPARE },
    7676        { 209, "Forbidden nickname",                                    0 },
    7777        { 210, "Buddy list too long",                                   0 },
    7878        { 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 },
    8181        { 218, "Already in that mode",                                  0 },
    8282        { 219, "Handle is already in opposite list",                    0 },
     
    113113        { 711, "Write is blocking",                                     STATUS_FATAL },
    114114        { 712, "Session is overloaded",                                 STATUS_FATAL },
    115         { 713, "Calling too rapidly",                                   0 },
     115        { 713, "Calling too rapidly",                                   STATUS_SB_IM_SPARE },
    116116        { 714, "Too many sessions",                                     STATUS_FATAL },
    117117        { 715, "Not expected/Invalid argument/action",                  0 },
  • protocols/nogaim.c

    rb1dc403 r531eabd  
    503503};
    504504
    505 static void imcb_ask_cb_free(void *data)
     505static void imcb_ask_auth_cb_no(void *data)
    506506{
    507507        struct imcb_ask_cb_data *cbd = data;
     508
     509        cbd->ic->acc->prpl->auth_deny(cbd->ic, cbd->handle);
    508510
    509511        g_free(cbd->handle);
     
    511513}
    512514
    513 static void imcb_ask_auth_cb_no(void *data)
     515static void imcb_ask_auth_cb_yes(void *data)
    514516{
    515517        struct imcb_ask_cb_data *cbd = data;
    516518
    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 
    526519        cbd->ic->acc->prpl->auth_allow(cbd->ic, cbd->handle);
    527520
    528         imcb_ask_cb_free(cbd);
     521        g_free(cbd->handle);
     522        g_free(cbd);
    529523}
    530524
     
    546540        data->handle = g_strdup(handle);
    547541        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
     546static void imcb_ask_add_cb_no(void *data)
     547{
     548        g_free(((struct imcb_ask_cb_data*) data)->handle);
     549        g_free(data);
    551550}
    552551
     
    557556        cbd->ic->acc->prpl->add_buddy(cbd->ic, cbd->handle, NULL);
    558557
    559         imcb_ask_cb_free(data);
     558        imcb_ask_add_cb_no(data);
    560559}
    561560
    562561void imcb_ask_add(struct im_connection *ic, const char *handle, const char *realname)
    563562{
    564         struct imcb_ask_cb_data *data;
     563        struct imcb_ask_cb_data *data = g_new0(struct imcb_ask_cb_data, 1);
    565564        char *s;
    566565
     
    570569        }
    571570
    572         data = g_new0(struct imcb_ask_cb_data, 1);
    573 
    574571        s = g_strdup_printf("The user %s is not in your buddy list yet. Do you want to add him/her now?", handle);
    575572
     
    577574        data->handle = g_strdup(handle);
    578575        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);
    582577}
    583578
  • protocols/purple/ft-direct.c

    rb1dc403 r531eabd  
    2828
    2929#include "bitlbee.h"
    30 #include "bpurple.h"
    3130
    3231#include <stdarg.h>
     
    208207void purple_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *handle)
    209208{
    210         struct purple_data *pd = ic->proto_data;
     209        PurpleAccount *pa = ic->proto_data;
    211210        struct prpl_xfer_data *px;
    212211
     
    214213           multi-threaded anyway. */
    215214        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);
    218216
    219217        ft->write = prpl_xfer_write;
  • protocols/purple/ft.c

    rb1dc403 r531eabd  
    2828
    2929#include "bitlbee.h"
    30 #include "bpurple.h"
    3130
    3231#include <stdarg.h>
     
    286285{
    287286        struct prpl_xfer_data *px = ft->data;
    288         struct purple_data *pd = px->ic->proto_data;
     287        PurpleAccount *pa = px->ic->proto_data;
    289288
    290289        /* xfer_new() will pick up this variable. It's a hack but we're not
    291290           multi-threaded anyway. */
    292291        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);
    295293}
    296294
  • protocols/purple/purple.c

    rb1dc403 r531eabd  
    2323
    2424#include "bitlbee.h"
    25 #include "bpurple.h"
    2625#include "help.h"
    2726
     
    4039static char *set_eval_display_name(set_t *set, char *value);
    4140
    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 
    5641struct im_connection *purple_ic_by_pa(PurpleAccount *pa)
    5742{
    5843        GSList *i;
    59         struct purple_data *pd;
    6044
    6145        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) {
    6447                        return i->data;
    6548                }
     
    307290{
    308291        struct im_connection *ic = imcb_new(acc);
    309         struct purple_data *pd;
     292        PurpleAccount *pa;
    310293
    311294        if ((local_bee != NULL && local_bee != acc->bee) ||
     
    323306        purple_connections = g_slist_prepend(purple_connections, ic);
    324307
    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);
    334313}
    335314
    336315static void purple_logout(struct im_connection *ic)
    337316{
    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);
    345320        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);
    349322}
    350323
     
    352325{
    353326        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         }
    361327
    362328        if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
    363                                                           who, pd->account)) == NULL) {
     329                                                          who, ic->proto_data)) == NULL) {
    364330                conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,
    365                                                pd->account, who);
     331                                               ic->proto_data, who);
    366332        }
    367333
     
    373339static GList *purple_away_states(struct im_connection *ic)
    374340{
    375         struct purple_data *pd = ic->proto_data;
     341        PurpleAccount *pa = ic->proto_data;
    376342        GList *st, *ret = NULL;
    377343
    378         for (st = purple_account_get_status_types(pd->account); st; st = st->next) {
     344        for (st = purple_account_get_status_types(pa); st; st = st->next) {
    379345                PurpleStatusPrimitive prim = purple_status_type_get_primitive(st->data);
    380346                if (prim != PURPLE_STATUS_AVAILABLE && prim != PURPLE_STATUS_OFFLINE) {
     
    388354static void purple_set_away(struct im_connection *ic, char *state_txt, char *message)
    389355{
    390         struct purple_data *pd = ic->proto_data;
    391         GList *status_types = purple_account_get_status_types(pd->account), *st;
     356        PurpleAccount *pa = ic->proto_data;
     357        GList *status_types = purple_account_get_status_types(pa), *st;
    392358        PurpleStatusType *pst = NULL;
    393359        GList *args = NULL;
     
    412378        }
    413379
    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",
    416381                                       TRUE, args);
    417382
     
    482447        PurpleBuddy *pb;
    483448        PurpleGroup *pg = NULL;
    484         struct purple_data *pd = ic->proto_data;
    485449
    486450        if (group && !(pg = purple_find_group(group))) {
     
    489453        }
    490454
    491         pb = purple_buddy_new(pd->account, who, NULL);
     455        pb = purple_buddy_new((PurpleAccount *) ic->proto_data, who, NULL);
    492456        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);
    496460}
    497461
     
    499463{
    500464        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);
    504467        if (pb != NULL) {
    505468                PurpleGroup *group;
    506469
    507470                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);
    509472
    510473                purple_blist_remove_buddy(pb);
    511474        }
    512475
    513         purple_gg_buddylist_export(pd->account->gc);
     476        purple_gg_buddylist_export(((PurpleAccount *) ic->proto_data)->gc);
    514477}
    515478
    516479static void purple_add_permit(struct im_connection *ic, char *who)
    517480{
    518         struct purple_data *pd = ic->proto_data;
    519 
    520         purple_privacy_permit_add(pd->account, who, FALSE);
     481        PurpleAccount *pa = ic->proto_data;
     482
     483        purple_privacy_permit_add(pa, who, FALSE);
    521484}
    522485
    523486static void purple_add_deny(struct im_connection *ic, char *who)
    524487{
    525         struct purple_data *pd = ic->proto_data;
    526 
    527         purple_privacy_deny_add(pd->account, who, FALSE);
     488        PurpleAccount *pa = ic->proto_data;
     489
     490        purple_privacy_deny_add(pa, who, FALSE);
    528491}
    529492
    530493static void purple_rem_permit(struct im_connection *ic, char *who)
    531494{
    532         struct purple_data *pd = ic->proto_data;
    533 
    534         purple_privacy_permit_remove(pd->account, who, FALSE);
     495        PurpleAccount *pa = ic->proto_data;
     496
     497        purple_privacy_permit_remove(pa, who, FALSE);
    535498}
    536499
    537500static void purple_rem_deny(struct im_connection *ic, char *who)
    538501{
    539         struct purple_data *pd = ic->proto_data;
    540 
    541         purple_privacy_deny_remove(pd->account, who, FALSE);
     502        PurpleAccount *pa = ic->proto_data;
     503
     504        purple_privacy_deny_remove(pa, who, FALSE);
    542505}
    543506
    544507static void purple_get_info(struct im_connection *ic, char *who)
    545508{
    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);
    549510}
    550511
     
    556517{
    557518        PurpleTypingState state = PURPLE_NOT_TYPING;
    558         struct purple_data *pd = ic->proto_data;
     519        PurpleAccount *pa = ic->proto_data;
    559520
    560521        if (flags & OPT_TYPING) {
     
    564525        }
    565526
    566         serv_send_typing(purple_account_get_connection(pd->account), who, state);
     527        serv_send_typing(purple_account_get_connection(pa), who, state);
    567528
    568529        return 1;
     
    598559        /* There went my nice afternoon. :-( */
    599560
    600         struct purple_data *pd = ic->proto_data;
    601         PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id);
     561        PurpleAccount *pa = ic->proto_data;
     562        PurplePlugin *prpl = purple_plugins_find_with_id(pa->protocol_id);
    602563        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);
    604565        PurpleMenuAction *mi;
    605566        GList *menu;
     
    636597        PurpleConversation *pc = gc->data;
    637598        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),
    641601                         purple_conv_chat_get_id(pcc),
    642602                         message && *message ? message : "Please join my chat",
     
    663623                                   set_t **sets)
    664624{
    665         struct purple_data *pd = ic->proto_data;
    666         PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id);
     625        PurpleAccount *pa = ic->proto_data;
     626        PurplePlugin *prpl = purple_plugins_find_with_id(pa->protocol_id);
    667627        PurplePluginProtocolInfo *pi = prpl->info->extra_info;
    668628        GHashTable *chat_hash;
     
    671631
    672632        if (!pi->chat_info || !pi->chat_info_defaults ||
    673             !(info = pi->chat_info(purple_account_get_connection(pd->account)))) {
     633            !(info = pi->chat_info(purple_account_get_connection(pa)))) {
    674634                imcb_error(ic, "Joining chatrooms not supported by this protocol");
    675635                return NULL;
    676636        }
    677637
    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))) {
    680639                purple_conversation_destroy(conv);
    681640        }
    682641
    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);
    686643
    687644        for (l = info; l; l = l->next) {
     
    697654        }
    698655
    699         serv_join_chat(purple_account_get_connection(pd->account), chat_hash);
     656        serv_join_chat(purple_account_get_connection(pa), chat_hash);
    700657
    701658        return NULL;
     
    1024981                pqad->yes(pqad->user_data, pqad->yes_i);
    1025982        }
     983        g_free(pqad);
    1026984}
    1027985
     
    1033991                pqad->no(pqad->user_data, pqad->no_i);
    1034992        }
    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);
    1044994}
    1045995
     
    10761026        q = g_strdup_printf("Request: %s\n\n%s\n\n%s", title, primary, secondary);
    10771027        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);
    10801029
    10811030        g_free(q);
     
    10841033}
    10851034
    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/*
     1036static void prplcb_request_test()
     1037{
     1038        fprintf( stderr, "bla\n" );
     1039}
     1040*/
    11621041
    11631042static PurpleRequestUiOps bee_request_uiops =
    11641043{
    1165         prplcb_request_input,
     1044        NULL,
    11661045        NULL,
    11671046        prplcb_request_action,
    11681047        NULL,
    11691048        NULL,
    1170         prplcb_close_request,
     1049        NULL,
    11711050        NULL,
    11721051};
  • protocols/skype/Makefile

    rb1dc403 r531eabd  
    66DATE := $(shell date +%Y-%m-%d)
    77INSTALL = install
     8ASCIIDOC = yes
    89
    9 
    10 ifdef ASCIIDOC
     10ifeq ($(ASCIIDOC),yes)
    1111MANPAGES = skyped.1
    1212else
     
    2929
    3030install-doc: doc
    31 ifdef ASCIIDOC
     31ifeq ($(ASCIIDOC),yes)
    3232        $(INSTALL) -d $(DESTDIR)$(MANDIR)/man1
    3333        $(INSTALL) -m644 $(MANPAGES) $(DESTDIR)$(MANDIR)/man1
  • protocols/twitter/twitter.c

    rb1dc403 r531eabd  
    852852}
    853853
    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 
    871854/** Convert the given bitlbee tweet ID, bitlbee username, or twitter tweet ID
    872855 *  into a twitter tweet ID.
     
    896879                        arg++;
    897880                }
    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) {
    899883                        bu = td->log[id].bu;
    900884                        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) {
    902890                        /* Allow normal tweet IDs as well; not a very useful
    903891                           feature but it's always been there. Just ignore
     
    909897        }
    910898        if (bu_) {
    911                 if (bu == &twitter_log_local_user) {
    912                         /* HACK alert. There's no bee_user object for the local
    913                          * user so just fake one for the few cmds that need it. */
    914                         twitter_log_local_user.handle = td->user;
    915                 } else {
    916                         /* Beware of dangling pointers! */
    917                         if (!g_slist_find(ic->bee->users, bu)) {
    918                                 bu = NULL;
    919                         }
    920                 }
    921899                *bu_ = bu;
    922900        }
     
    1011989                in_reply_to = id;
    1012990                allow_post = TRUE;
    1013         } else if (g_strcasecmp(cmd[0], "url") == 0) {
    1014                 id = twitter_message_id_from_command_arg(ic, cmd[1], &bu);
    1015                 if (!id) {
    1016                         twitter_log(ic, "Tweet `%s' does not exist", cmd[1]);
    1017                 } else {
    1018                         /* More common link is twitter.com/$UID/status/$ID (and that's
    1019                          * what this will 302 to) but can't generate that since for RTs,
    1020                          * bu here points at the retweeter while id contains the id of
    1021                          * the original message. */
    1022                         twitter_log(ic, "https://twitter.com/statuses/%lld", id);
    1023                 }
    1024                 goto eof;
    1025 
    1026991        } else if (g_strcasecmp(cmd[0], "post") == 0) {
    1027992                message += 5;
  • protocols/twitter/twitter.h

    rb1dc403 r531eabd  
    101101struct twitter_log_data {
    102102        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. */
    106104};
    107105
     
    112110 */
    113111extern GSList *twitter_connections;
    114 
    115 /**
    116  * Evil hack: Fake bee_user which will always point at the local user.
    117  * Sometimes used as a return value by twitter_message_id_from_command_arg.
    118  * NOT thread safe but don't you dare to even think of ever making BitlBee
    119  * threaded. :-)
    120  */
    121 extern bee_user_t twitter_log_local_user;
    122112
    123113void twitter_login_finish(struct im_connection *ic);
  • protocols/twitter/twitter_lib.c

    rb1dc403 r531eabd  
    460460#endif
    461461
    462 static void expand_entities(char **text, const json_value *node);
     462static char* expand_entities(char* text, const json_value *entities);
    463463
    464464/**
     
    473473{
    474474        struct twitter_xml_status *txs;
    475         const json_value *rt = NULL;
     475        const json_value *rt = NULL, *entities = NULL;
    476476
    477477        if (node->type != json_object) {
     
    501501                } else if (strcmp("in_reply_to_status_id", k) == 0 && v->type == json_integer) {
    502502                        txs->reply_to = v->u.integer;
     503                } else if (strcmp("entities", k) == 0 && v->type == json_object) {
     504                        entities = v;
    503505                }
    504506        }
     
    514516                        txs_free(rtxs);
    515517                }
    516         } else {
    517                 expand_entities(&txs->text, node);
     518        } else if (entities) {
     519                txs->text = expand_entities(txs->text, entities);
    518520        }
    519521
     
    532534{
    533535        struct twitter_xml_status *txs;
     536        const json_value *entities = NULL;
    534537
    535538        if (node->type != json_object) {
     
    558561        }
    559562
    560         expand_entities(&txs->text, node);
     563        if (entities) {
     564                txs->text = expand_entities(txs->text, entities);
     565        }
    561566
    562567        if (txs->text && txs->user && txs->id) {
     
    568573}
    569574
    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 
     575static char* expand_entities(char* text, const json_value *entities)
     576{
    590577        JSON_O_FOREACH(entities, k, v) {
    591578                int i;
     
    599586
    600587                for (i = 0; i < v->u.array.length; i++) {
    601                         const char *format = "%s%s <%s>%s";
    602 
    603588                        if (v->u.array.values[i]->type != json_object) {
    604589                                continue;
     
    607592                        const char *kort = json_o_str(v->u.array.values[i], "url");
    608593                        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");
    610594                        char *pos, *new;
    611595
    612                         if (!kort || !disp || !(pos = strstr(*text, kort))) {
     596                        if (!kort || !disp || !(pos = strstr(text, kort))) {
    613597                                continue;
    614598                        }
    615                         if (quote_url && strstr(full, quote_url)) {
    616                                 format = "%s<%s> [%s]%s";
    617                                 disp = quote_text;
    618                         }
    619599
    620600                        *pos = '\0';
    621                         new = g_strdup_printf(format, *text, kort,
     601                        new = g_strdup_printf("%s%s <%s>%s", text, kort,
    622602                                              disp, pos + strlen(kort));
    623603
    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;
    630610}
    631611
     
    701681        if (g_strcasecmp(txs->user->screen_name, td->user) == 0) {
    702682                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;
    705683        }
    706684
     
    854832
    855833        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);
    857835        g_free(last_id_str);
    858836}
     
    884862
    885863                imcb_error(ic, "Stream closed (%s)", req->status_string);
    886                 if (req->status_code == 401) {
    887                         imcb_error(ic, "Check your system clock.");
    888                 }
    889864                imc_logout(ic, TRUE);
    890865                return;
  • protocols/yahoo/yahoo.c

    rb1dc403 r531eabd  
    733733                inp = l->data;
    734734                if (inp->h == tag) {
    735                         byahoo_inputs = g_slist_remove(byahoo_inputs, inp);
    736735                        g_free(inp->d);
    737736                        g_free(inp);
     737                        byahoo_inputs = g_slist_remove(byahoo_inputs, inp);
    738738                        break;
    739739                }
  • storage_xml.c

    rb1dc403 r531eabd  
    103103        if (protocol) {
    104104                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                 }
    109105                local = protocol_account_islocal(protocol);
    110106        }
     
    128124                }
    129125        } else {
    130                 g_free(pass_cr);
    131                 g_free(password);
    132126                return XT_ABORT;
    133127        }
     
    203197        fn = g_strconcat(global.conf->configdir, xd->given_nick, ".xml", NULL);
    204198        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;
    210200                goto error;
    211201        }
     
    269259
    270260
     261static gboolean xml_generate_nick(gpointer key, gpointer value, gpointer data);
    271262static void xml_generate_settings(struct xt_node *cur, set_t **head);
    272263
     
    301292
    302293        for (acc = irc->b->accounts; acc; acc = acc->next) {
    303                 GHashTableIter iter;
    304                 gpointer key, value;
    305294                unsigned char *pass_cr;
    306295                char *pass_b64;
     
    323312                g_free(pass_b64);
    324313
    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);
    332322
    333323                xml_generate_settings(cur, &acc->set);
     
    353343
    354344        return root;
     345}
     346
     347static 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;
    355356}
    356357
     
    387388        strcat(path, ".XXXXXX");
    388389        if ((fd = mkstemp(path)) < 0) {
    389                 goto error;
     390                irc_rootmsg(irc, "Error while opening configuration file.");
     391                return STORAGE_OTHER_ERROR;
    390392        }
    391393
     
    409411
    410412error:
    411         irc_rootmsg(irc, "Write error: %s", g_strerror(errno));
     413        irc_rootmsg(irc, "Write error. Disk full?");
    412414        ret = STORAGE_OTHER_ERROR;
    413415
Note: See TracChangeset for help on using the changeset viewer.