Changeset b1dc403


Ignore:
Timestamp:
2015-05-04T21:58:50Z (4 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Children:
5726a0d
Parents:
531eabd (diff), 5ca1416 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Catch up with master.

Files:
3 added
3 deleted
49 edited

Legend:

Unmodified
Added
Removed
  • .travis.yml

    r531eabd rb1dc403  
    11language: c
    2 script: ./configure && make check && dpkg-buildpackage -uc -us
     2
     3script:
     4 - ./configure
     5 - make check
     6 - dpkg-buildpackage -uc -us
     7
    38before_install:
    49 - sudo apt-get update -qq
     
    712 - sudo dpkg -i *.deb
    813
     14env:
     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
     20addons:
     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
     30notifications:
     31  email: false
  • Makefile

    r531eabd rb1dc403  
    2525
    2626doc:
     27ifdef DOC
    2728        $(MAKE) -C doc
     29endif
    2830
    2931uninstall: uninstall-bin uninstall-doc
     
    7375
    7476install-doc:
     77ifdef DOC
    7578        $(MAKE) -C doc install
     79endif
    7680ifdef SKYPE_PI
    7781        $(MAKE) -C protocols/skype install-doc
     
    7983
    8084uninstall-doc:
     85ifdef DOC
    8186        $(MAKE) -C doc uninstall
     87endif
    8288ifdef SKYPE_PI
    8389        $(MAKE) -C protocols/skype uninstall-doc
     
    153159        x=$$(basename $$(pwd)); \
    154160        cd ..; \
    155         tar czf $$x.tar.gz --exclude-from=.gitignore $$x
     161        tar czf $$x.tar.gz --exclude=debian --exclude=.git* --exclude=.depend $$x
    156162
    157163$(subdirs):
  • bitlbee.h

    r531eabd rb1dc403  
    3636
    3737#define PACKAGE "BitlBee"
    38 #define BITLBEE_VERSION "3.2.2"
     38#define BITLBEE_VERSION "3.4"
    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, 2, 2)
     41#define BITLBEE_VERSION_CODE BITLBEE_VER(3, 4, 0)
    4242
    4343#define MAX_STRING 511
  • configure

    r531eabd rb1dc403  
    3838purple=0
    3939
     40doc=1
    4041debug=0
    4142strip=1
     
    5657GLIB_MIN_VERSION=2.16
    5758
    58 echo BitlBee configure
    59 
    6059# Cygwin and Darwin don't support PIC/PIE
    6160case "$arch" in
    62     CYGWIN* )
    63         pie=0;;
    64     Darwin )
    65         pie=0;;
     61        CYGWIN* )
     62                pie=0;;
     63        Darwin )
     64                pie=0;;
    6665esac
     66
     67get_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
     84if [ "$1" = "--dump-version" ]; then
     85        srcdir=$(cd $(dirname $0);pwd)
     86        get_version
     87        echo $BITLBEE_VERSION
     88        exit
     89fi
     90
     91echo BitlBee configure
    6792
    6893while [ -n "$1" ]; do
     
    96121--rpc=0/1       Disable/enable RPC interface            $rpc
    97122
     123--doc=0/1       Disable/enable help.txt generation      $doc
    98124--debug=0/1     Disable/enable debugging                $debug
    99125--strip=0/1     Disable/enable binary stripping         $strip
     
    450476        ret=1
    451477        echo "$RESOLV_NS_TESTCODE" | $CC -o $TMPFILE -x c - $LIBRESOLV >/dev/null 2>/dev/null
    452         if [ "$?" = "0" ]; then
    453                 ret=0
    454         fi
     478        if [ "$?" = "0" ]; then
     479                ret=0
     480        fi
    455481
    456482        rm -f $TMPFILE
     
    465491                if [ -f $i/libresolv.a ]; then
    466492                        echo "$RESOLV_NS_TESTCODE" | $CC -o $TMPFILE -x c - -Wl,$i/libresolv.a >/dev/null 2>/dev/null
    467                         if [ "$?" = "0" ]; then
    468                                 ret=0
    469                         fi
     493                        if [ "$?" = "0" ]; then
     494                                ret=0
     495                        fi
    470496                fi
    471497        done
     
    477503detect_nameser_has_ns_types()
    478504{
    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
     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
    490516}
    491517
     
    548574if detect_resolv_dynamic || detect_resolv_static; then
    549575        echo '#define HAVE_RESOLV_A' >> config.h
    550     if detect_resolv_ns_dynamic || detect_resolv_ns_static; then
    551             echo '#define HAVE_RESOLV_A_WITH_NS' >> config.h
    552     fi
    553 else
    554     echo 'Insufficient resolv routines. Jabber server must be set explicitly'
     576        if detect_resolv_ns_dynamic || detect_resolv_ns_static; then
     577                echo '#define HAVE_RESOLV_A_WITH_NS' >> config.h
     578        fi
     579else
     580        echo 'Insufficient resolv routines. Jabber server must be set explicitly'
    555581fi
    556582
     
    649675fi
    650676
    651 if [ ! -e doc/user-guide/help.txt ] && ! type xmlto > /dev/null 2> /dev/null; then
    652         echo
    653         echo 'WARNING: Building from an unreleased source tree without prebuilt helpfile.'
    654         echo 'Install xmlto if you want online help to work.'
    655 fi
    656 
    657 REAL_BITLBEE_VERSION=`grep '^#define BITLBEE_VERSION ' $srcdir/bitlbee.h | sed 's/.*\"\(.*\)\".*/\1/'`
    658 echo
    659 if [ -z "$BITLBEE_VERSION" -a -d .bzr ] && type bzr > /dev/null 2> /dev/null; then
    660         nick=`bzr nick`
    661         if [ -n "$nick" -a "$nick" != "bitlbee" ]; then
    662                 nick="-$nick"
     677if [ "$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.'
    663685        else
    664                 nick=""
    665         fi
    666         rev=`bzr revno`
    667         echo 'Using bzr revision #'$rev' as version number'
    668         BITLBEE_VERSION=$REAL_BITLBEE_VERSION-bzr$nick-$rev
    669 fi
    670 
    671 if [ -z "$BITLBEE_VERSION" -a -d .git ] && type git > /dev/null 2> /dev/null; then
    672         rev=`git describe --long --tags`-`git rev-parse --abbrev-ref HEAD`
    673         echo 'Using '$rev' as git version number'
    674         BITLBEE_VERSION=$rev-git
    675 fi
    676 
    677 if [ -n "$BITLBEE_VERSION" ]; then
     686                echo "DOC=1" >> Makefile.settings
     687        fi
     688
     689        if [ "$skype" = "1" -o "$skype" = "plugin" ]; then
     690                # skype also needs asciidoc
     691                if ! type a2x > /dev/null 2> /dev/null; then
     692                        echo
     693                        echo 'WARNING: The skyped man page requires asciidoc. It will not be generated.'
     694                else
     695                        echo "ASCIIDOC=1" >> Makefile.settings
     696                fi
     697        fi
     698fi
     699
     700get_version
     701
     702if [ "$BITLBEE_VERSION" != "$REAL_BITLBEE_VERSION" ]; then
    678703        echo 'Spoofing version number: '$BITLBEE_VERSION
    679704        echo '#undef BITLBEE_VERSION' >> config.h
    680705        echo '#define BITLBEE_VERSION "'$BITLBEE_VERSION'"' >> config.h
    681706        echo
    682 else
    683         # for pkg-config
    684         BITLBEE_VERSION=$REAL_BITLBEE_VERSION
    685707fi
    686708
  • doc/CHANGES

    r531eabd rb1dc403  
    11This ChangeLog mostly lists changes relevant to users. A full log can be
    2 found in the bzr commit logs, for example you can try:
    3 
    4 http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on
     2found in the git commit logs, for example you can try:
     3
     4https://github.com/bitlbee/bitlbee/commits/master
     5
     6Version 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
     47Finished 25 Mar 2015
    548
    649Version 3.2.2:
  • doc/user-guide/commands.xml

    r531eabd rb1dc403  
    121121                        <description>
    122122                                <para>
    123                                         This commands deletes an account from your account list. You should signoff the account before deleting it.
     123                                        This command deletes an account from your account list. You should signoff the account before deleting it.
    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>
    855856                        </variablelist>
    856857
  • doc/user-guide/misc.xml

    r531eabd rb1dc403  
    409409</sect1>
    410410
     411<sect1 id="whatsnew030400">
     412<title>New stuff in BitlBee 3.4</title>
     413
     414<para>
     415Lots 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>
     430See the full changelog for details!
     431</para>
     432
     433</sect1>
     434
    411435</chapter>
  • help.c

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

    r531eabd rb1dc403  
    776776        }
    777777
     778        child_list = g_slist_remove(child_list, c);
     779
    778780        g_free(c->host);
    779781        g_free(c->nick);
     
    781783        g_free(c->password);
    782784        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

    r531eabd rb1dc403  
    764764                        irc_rootmsg(irc,
    765765                                    "Welcome to the BitlBee gateway!\n\n"
     766                                    "Running %s %s\n\n"
    766767                                    "If you've never used BitlBee before, please do read the help "
    767768                                    "information using the \x02help\x02 command. Lots of FAQs are "
    768769                                    "answered there.\n"
    769770                                    "If you already have an account on this server, just use the "
    770                                     "\x02identify\x02 command to identify yourself.");
     771                                    "\x02identify\x02 command to identify yourself.",
     772                                    PACKAGE, BITLBEE_VERSION);
    771773
    772774                        /* This is for bug #209 (use PASS to identify to NickServ). */
  • irc.h

    r531eabd rb1dc403  
    299299void irc_channel_name_strip(char *name);
    300300int irc_channel_name_cmp(const char *a_, const char *b_);
     301char *irc_channel_name_gen(irc_t *irc, const char *name);
     302gboolean irc_channel_name_hint(irc_channel_t *ic, const char *name);
    301303void irc_channel_update_ops(irc_channel_t *ic, char *value);
    302304char *set_eval_irc_channel_ops(struct set *set, char *value);
  • irc_channel.c

    r531eabd rb1dc403  
    556556}
    557557
     558gboolean 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
     588char *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
     618gboolean 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
    558638static gint irc_channel_user_cmp(gconstpointer a_, gconstpointer b_)
    559639{
  • irc_im.c

    r531eabd rb1dc403  
    235235                        } else {
    236236                                /* Modules can swallow messages. */
    237                                 return TRUE;
     237                                goto cleanup;
    238238                        }
    239239                }
     
    250250        wrapped = word_wrap(msg, 425);
    251251        irc_send_msg(iu, "PRIVMSG", dst, wrapped, prefix);
    252 
    253252        g_free(wrapped);
     253
     254cleanup:
    254255        g_free(prefix);
    255256        g_free(msg);
     
    291292
    292293        irc_send_msg((irc_user_t *) bu->ui_data, "NOTICE", irc->user->nick, msg->str, NULL);
     294
     295        g_string_free(msg, TRUE);
    293296
    294297        return TRUE;
     
    693696static gboolean bee_irc_chat_name_hint(bee_t *bee, struct groupchat *c, const char *name)
    694697{
    695         irc_t *irc = bee->ui_data;
    696         irc_channel_t *ic = c->ui_data, *oic;
    697         char stripped[MAX_NICK_LENGTH + 1], *full_name;
    698 
    699         if (ic == NULL) {
    700                 return FALSE;
    701         }
    702 
    703         /* Don't rename a channel if the user's in it already. */
    704         if (ic->flags & IRC_CHANNEL_JOINED) {
    705                 return FALSE;
    706         }
    707 
    708         strncpy(stripped, name, MAX_NICK_LENGTH);
    709         stripped[MAX_NICK_LENGTH] = '\0';
    710         irc_channel_name_strip(stripped);
    711         if (set_getbool(&bee->set, "lcnicks")) {
    712                 nick_lc(irc, stripped);
    713         }
    714 
    715         if (stripped[0] == '\0') {
    716                 return FALSE;
    717         }
    718 
    719         full_name = g_strdup_printf("#%s", stripped);
    720         if ((oic = irc_channel_by_name(irc, full_name))) {
    721                 char *type, *chat_type;
    722 
    723                 type = set_getstr(&oic->set, "type");
    724                 chat_type = set_getstr(&oic->set, "chat_type");
    725 
    726                 if (type && chat_type && oic->data == FALSE &&
    727                     strcmp(type, "chat") == 0 &&
    728                     strcmp(chat_type, "groupchat") == 0) {
    729                         /* There's a channel with this name already, but it looks
    730                            like it's not in use yet. Most likely the IRC client
    731                            rejoined the channel after a reconnect. Remove it so
    732                            we can reuse its name. */
    733                         irc_channel_free(oic);
    734                 } else {
    735                         g_free(full_name);
    736                         return FALSE;
    737                 }
    738         }
    739 
    740         g_free(ic->name);
    741         ic->name = full_name;
    742 
    743         return TRUE;
     698        return irc_channel_name_hint(c->ui_data, name);
    744699}
    745700
  • irc_send.c

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

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

    r531eabd rb1dc403  
    9898        GSList *l, *n;
    9999
    100         if (params == NULL) {
     100        if (!params) {
    101101                return;
    102102        }
     
    104104        for (l = *params; l; l = n) {
    105105                n = l->next;
    106 
    107                 if (strncmp((char *) l->data, key, key_len) == 0 &&
    108                     ((char *) l->data)[key_len] == '=') {
    109                         g_free(l->data);
    110                         *params = g_slist_remove(*params, l->data);
     106                char *data = l->data;
     107
     108                if (strncmp(data, key, key_len) == 0 && data[key_len] == '=') {
     109                        *params = g_slist_remove(*params, data);
     110                        g_free(data);
    111111                }
    112112        }
  • lib/proxy.c

    r531eabd rb1dc403  
    6363static int proxy_connect_none(const char *host, unsigned short port_, struct PHB *phb);
    6464
    65 static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition cond)
     65static 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
     74static gboolean proxy_connected(gpointer data, gint source, b_input_condition cond)
    6675{
    6776        struct PHB *phb = data;
     
    8089                                dup2(new_fd, source);
    8190                                closesocket(new_fd);
    82                                 phb->inpa = b_input_add(source, B_EV_IO_WRITE, gaim_io_connected, phb);
     91                                phb->inpa = b_input_add(source, B_EV_IO_WRITE, proxy_connected, phb);
    8392                                return FALSE;
    8493                        }
    8594                }
    86                 freeaddrinfo(phb->gai);
    8795                closesocket(source);
    88                 b_event_remove(phb->inpa);
    89                 phb->inpa = 0;
    90                 if (phb->proxy_func) {
    91                         phb->proxy_func(phb->proxy_data, -1, B_EV_IO_READ);
    92                 } else {
    93                         phb->func(phb->data, -1, B_EV_IO_READ);
    94                         g_free(phb);
    95                 }
    96                 return FALSE;
    97         }
     96                source = -1;
     97                /* socket is dead, but continue to clean up */
     98        } else {
     99                sock_make_blocking(source);
     100        }
     101
    98102        freeaddrinfo(phb->gai);
    99         sock_make_blocking(source);
    100103        b_event_remove(phb->inpa);
    101104        phb->inpa = 0;
     
    160163                        continue;
    161164                } else {
    162                         phb->inpa = b_input_add(fd, B_EV_IO_WRITE, gaim_io_connected, phb);
     165                        phb->inpa = b_input_add(fd, B_EV_IO_WRITE, proxy_connected, phb);
    163166                        phb->fd = fd;
    164167
     
    206209        }
    207210
    208         close(source);
    209         phb->func(phb->data, -1, B_EV_IO_READ);
    210         g_free(phb->host);
    211         g_free(phb);
    212 
    213         return FALSE;
     211        return phb_close(phb);
    214212}
    215213
     
    226224        len = sizeof(error);
    227225        if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
    228                 close(source);
    229                 phb->func(phb->data, -1, B_EV_IO_READ);
    230                 g_free(phb->host);
    231                 g_free(phb);
    232                 return FALSE;
     226                return phb_close(phb);
    233227        }
    234228        sock_make_blocking(source);
     
    237231                   phb->host, phb->port);
    238232        if (send(source, cmd, strlen(cmd), 0) < 0) {
    239                 close(source);
    240                 phb->func(phb->data, -1, B_EV_IO_READ);
    241                 g_free(phb->host);
    242                 g_free(phb);
    243                 return FALSE;
     233                return phb_close(phb);
    244234        }
    245235
     
    252242                g_free(t2);
    253243                if (send(source, cmd, strlen(cmd), 0) < 0) {
    254                         close(source);
    255                         phb->func(phb->data, -1, B_EV_IO_READ);
    256                         g_free(phb->host);
    257                         g_free(phb);
    258                         return FALSE;
     244                        return phb_close(phb);
    259245                }
    260246        }
     
    262248        g_snprintf(cmd, sizeof(cmd), "\r\n");
    263249        if (send(source, cmd, strlen(cmd), 0) < 0) {
    264                 close(source);
    265                 phb->func(phb->data, -1, B_EV_IO_READ);
    266                 g_free(phb->host);
    267                 g_free(phb);
    268                 return FALSE;
     250                return phb_close(phb);
    269251        }
    270252
     
    302284        }
    303285
    304         close(source);
    305         phb->func(phb->data, -1, B_EV_IO_READ);
    306         g_free(phb->host);
    307         g_free(phb);
    308 
    309         return FALSE;
     286        return phb_close(phb);
    310287}
    311288
     
    323300        len = sizeof(error);
    324301        if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
    325                 close(source);
    326                 phb->func(phb->data, -1, B_EV_IO_READ);
    327                 g_free(phb->host);
    328                 g_free(phb);
    329                 return FALSE;
     302                return phb_close(phb);
    330303        }
    331304        sock_make_blocking(source);
     
    333306        /* XXX does socks4 not support host name lookups by the proxy? */
    334307        if (!(hp = gethostbyname(phb->host))) {
    335                 close(source);
    336                 phb->func(phb->data, -1, B_EV_IO_READ);
    337                 g_free(phb->host);
    338                 g_free(phb);
    339                 return FALSE;
     308                return phb_close(phb);
    340309        }
    341310
     
    350319        packet[8] = 0;
    351320        if (write(source, packet, 9) != 9) {
    352                 close(source);
    353                 phb->func(phb->data, -1, B_EV_IO_READ);
    354                 g_free(phb->host);
    355                 g_free(phb);
    356                 return FALSE;
     321                return phb_close(phb);
    357322        }
    358323
     
    383348
    384349        if (read(source, buf, 10) < 10) {
    385                 close(source);
    386                 phb->func(phb->data, -1, B_EV_IO_READ);
    387                 g_free(phb->host);
    388                 g_free(phb);
    389                 return FALSE;
     350                return phb_close(phb);
    390351        }
    391352        if ((buf[0] != 0x05) || (buf[1] != 0x00)) {
    392                 close(source);
    393                 phb->func(phb->data, -1, B_EV_IO_READ);
    394                 g_free(phb->host);
    395                 g_free(phb);
    396                 return FALSE;
     353                return phb_close(phb);
    397354        }
    398355
     
    420377
    421378        if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) {
    422                 close(source);
    423                 phb->func(phb->data, -1, B_EV_IO_READ);
    424                 g_free(phb->host);
    425                 g_free(phb);
     379                phb_close(phb);
    426380                return;
    427381        }
     
    438392
    439393        if (read(source, buf, 2) < 2) {
    440                 close(source);
    441                 phb->func(phb->data, -1, B_EV_IO_READ);
    442                 g_free(phb->host);
    443                 g_free(phb);
    444                 return FALSE;
     394                return phb_close(phb);
    445395        }
    446396
    447397        if ((buf[0] != 0x01) || (buf[1] != 0x00)) {
    448                 close(source);
    449                 phb->func(phb->data, -1, B_EV_IO_READ);
    450                 g_free(phb->host);
    451                 g_free(phb);
    452                 return FALSE;
     398                return phb_close(phb);
    453399        }
    454400
     
    466412
    467413        if (read(source, buf, 2) < 2) {
    468                 close(source);
    469                 phb->func(phb->data, -1, B_EV_IO_READ);
    470                 g_free(phb->host);
    471                 g_free(phb);
    472                 return FALSE;
     414                return phb_close(phb);
    473415        }
    474416
    475417        if ((buf[0] != 0x05) || (buf[1] == 0xff)) {
    476                 close(source);
    477                 phb->func(phb->data, -1, B_EV_IO_READ);
    478                 g_free(phb->host);
    479                 g_free(phb);
    480                 return FALSE;
     418                return phb_close(phb);
    481419        }
    482420
     
    489427                memcpy(buf + 2 + i + 1, proxypass, j);
    490428                if (write(source, buf, 3 + i + j) < 3 + i + j) {
    491                         close(source);
    492                         phb->func(phb->data, -1, B_EV_IO_READ);
    493                         g_free(phb->host);
    494                         g_free(phb);
    495                         return FALSE;
     429                        return phb_close(phb);
    496430                }
    497431
     
    517451        len = sizeof(error);
    518452        if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
    519                 close(source);
    520                 phb->func(phb->data, -1, B_EV_IO_READ);
    521                 g_free(phb->host);
    522                 g_free(phb);
    523                 return FALSE;
     453                return phb_close(phb);
    524454        }
    525455        sock_make_blocking(source);
     
    539469
    540470        if (write(source, buf, i) < i) {
    541                 close(source);
    542                 phb->func(phb->data, -1, B_EV_IO_READ);
    543                 g_free(phb->host);
    544                 g_free(phb);
    545                 return FALSE;
     471                return phb_close(phb);
    546472        }
    547473
  • lib/ssl_gnutls.c

    r531eabd rb1dc403  
    124124
    125125        if (conn->fd < 0) {
     126                g_free(conn->hostname);
    126127                g_free(conn);
    127128                return NULL;
     
    314315        if (source == -1) {
    315316                conn->func(conn->data, 0, NULL, cond);
     317                g_free(conn->hostname);
    316318                g_free(conn);
    317319                return FALSE;
     
    355357                        conn->func(conn->data, 0, NULL, cond);
    356358
    357                         gnutls_deinit(conn->session);
    358                         closesocket(conn->fd);
    359 
    360                         g_free(conn);
     359                        ssl_disconnect(conn);
    361360                }
    362361        } else {
     
    364363                        conn->func(conn->data, stver, NULL, cond);
    365364
    366                         gnutls_deinit(conn->session);
    367                         closesocket(conn->fd);
    368 
    369                         g_free(conn);
     365                        ssl_disconnect(conn);
    370366                } else {
    371367                        /* For now we can't handle non-blocking perfectly everywhere... */
  • nick.c

    r531eabd rb1dc403  
    214214}
    215215
     216/* Used for nicks and channel names too! */
     217void 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
    216232void nick_dedupe(bee_user_t *bu, char nick[MAX_NICK_LENGTH + 1])
    217233{
     
    224240        while (!nick_ok(irc, nick) ||
    225241               ((iu = irc_user_by_name(irc, nick)) && iu->bu != bu)) {
    226                 if (strlen(nick) < (MAX_NICK_LENGTH - 1)) {
    227                         nick[strlen(nick) + 1] = 0;
    228                         nick[strlen(nick)] = '_';
    229                 } else {
    230                         /* We've got no more space for underscores,
    231                            so truncate it and replace the last three
    232                            chars with a random "_XX" suffix */
    233                         int len = truncate_utf8(nick, MAX_NICK_LENGTH - 3);
    234                         nick[len] = '_';
    235                         g_snprintf(nick + len + 1, 3, "%2x", rand());
    236                 }
     242
     243                underscore_dedupe(nick);
    237244
    238245                if (inf_protection-- == 0) {
  • nick.h

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

    r531eabd rb1dc403  
    287287void otr_irc_free(irc_t *irc)
    288288{
     289        set_t *s;
    289290        otr_t *otr = irc->otr;
    290291
     
    292293        b_event_remove(otr->timer);
    293294        otrl_userstate_free(otr->us);
     295
     296        s = set_find(&irc->b->set, "otr_policy");
     297        g_slist_free(s->eval_data);
     298
    294299        if (otr->keygen) {
    295300                kill(otr->keygen, SIGTERM);
     
    434439                                            ic->acc->user, ic->acc->prpl->name, iu->bu->handle, msg, &newmsg,
    435440                                            &tlvs, NULL, NULL, NULL);
     441
     442        if (tlvs) {
     443                otrl_tlv_free(tlvs);
     444        }
    436445
    437446        if (ignore_msg) {
     
    472481                /* libotr wants us to replace our message */
    473482                /* NB: caller will free old msg */
    474                 msg = g_strdup(otrmsg);
     483                msg = st ? NULL : g_strdup(otrmsg);
    475484                otrl_message_free(otrmsg);
    476485        }
     
    13251334
    13261335        log_message(LOGLVL_INFO, "otr: %s", msg);
     1336
     1337        g_free(msg);
    13271338}
    13281339
     
    20752086        }
    20762087}
    2077 
    2078 /* vim: set noet ts=4 sw=4: */
  • protocols/bee.h

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

    r531eabd rb1dc403  
    6868        }
    6969
     70        bee->users = g_slist_remove(bee->users, bu);
     71
    7072        g_free(bu->handle);
    7173        g_free(bu->fullname);
     
    7476        g_free(bu->status_msg);
    7577        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, char *msg, uint32_t flags, time_t sent_at)
     249void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, uint32_t flags, time_t sent_at)
    250250{
    251251        bee_t *bee = ic->bee;
  • protocols/jabber/Makefile

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

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

    r531eabd rb1dc403  
    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);
    29 static int jabber_iq_disco_server(struct im_connection *ic);
    3029
    3130xt_status jabber_pkt_iq(struct xt_node *node, gpointer data)
     
    374373static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
    375374{
     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");
    390391
    391392                if (jid && sub) {
     
    396397                                if (name) {
    397398                                        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);
    398405                                }
    399406                        } else if (strcmp(sub, "remove") == 0) {
     
    855862                                                 struct xt_node *node, struct xt_node *orig);
    856863
    857 static int jabber_iq_disco_server(struct im_connection *ic)
     864int jabber_iq_disco_server(struct im_connection *ic)
    858865{
    859866        struct xt_node *node, *iq;
  • protocols/jabber/jabber.c

    r531eabd rb1dc403  
    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 
    6563        s = set_add(&acc->set, "display_name", NULL, NULL, acc);
    6664
     
    8381        s = set_add(&acc->set, "server", NULL, set_eval_account, acc);
    8482        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        }
    8589
    8690        s = set_add(&acc->set, "ssl", "false", set_eval_bool, acc);
     
    121125
    122126        jd->fd = jd->r_inpa = jd->w_inpa = -1;
     127
     128        if (strcmp(acc->prpl->name, "hipchat") == 0) {
     129                jd->flags |= JFLAG_HIPCHAT;
     130        }
    123131
    124132        if (jd->server == NULL) {
     
    656664{
    657665        struct prpl *ret = g_new0(struct prpl, 1);
     666        struct prpl *hipchat = NULL;
    658667
    659668        ret->name = "jabber";
     
    686695
    687696        register_protocol(ret);
    688 }
     697
     698        /* Another one for hipchat, which has completely different logins */
     699        hipchat = g_memdup(ret, sizeof(struct prpl));
     700        hipchat->name = "hipchat";
     701        register_protocol(hipchat);
     702}
  • protocols/jabber/jabber.h

    r531eabd rb1dc403  
    4848
    4949        JFLAG_GTALK =  0x100000,        /* Is Google Talk, as confirmed by iq discovery */
     50        JFLAG_HIPCHAT = 0x200000,       /* Is hipchat, because prpl->name says so */
    5051
    5152        JFLAG_SASL_FB = 0x10000,        /* Trying Facebook authentication. */
     
    235236#define XMLNS_IBB          "http://jabber.org/protocol/ibb"                      /* XEP-0047 */
    236237
     238/* Hipchat protocol extensions*/
     239#define XMLNS_HIPCHAT         "http://hipchat.com"
     240#define XMLNS_HIPCHAT_PROFILE "http://hipchat.com/protocol/profile"
     241
    237242/* jabber.c */
    238243void jabber_connect(struct im_connection *ic);
     
    249254xt_status jabber_iq_query_server(struct im_connection *ic, char *jid, char *xmlns);
    250255void jabber_iq_version_send(struct im_connection *ic, struct jabber_buddy *bud, void *data);
     256int jabber_iq_disco_server(struct im_connection *ic);
    251257
    252258/* si.c */
     
    341347void jabber_chat_invite(struct groupchat *c, char *who, char *message);
    342348
     349/* hipchat.c */
     350int jabber_get_hipchat_profile(struct im_connection *ic);
     351xt_status jabber_parse_hipchat_profile(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
     352xt_status hipchat_handle_success(struct im_connection *ic, struct xt_node *node);
     353
    343354#endif
  • protocols/jabber/jabber_util.c

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

    r531eabd rb1dc403  
    2323
    2424#include "jabber.h"
    25 #include "sha1.h"
    2625#include "lib/ftutil.h"
    2726#include <poll.h>
     
    4241
    4342        /* SHA1( SID + Initiator JID + Target JID) */
    44         char *pseudoadr;
     43        char *pseudoaddr;
    4544
    4645        gint connect_timeout;
     
    130129        }
    131130
    132         g_free(bt->pseudoadr);
     131        g_free(bt->pseudoaddr);
    133132
    134133        while (bt->streamhosts) {
     
    254253}
    255254
     255void 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
    256280/* Bad luck */
    257281void jabber_bs_canceled(file_transfer_t *ft, char *reason)
     
    260284
    261285        imcb_log(tf->ic, "File transfer aborted: %s", reason);
     286}
     287
     288static 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 */
     301static 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
     308static 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;
    262317}
    263318
     
    270325        struct jabber_data *jd = ic->proto_data;
    271326        struct jabber_transfer *tf = NULL;
    272         GSList *tflist;
    273327        struct bs_transfer *bt;
    274328        GSList *shlist = NULL;
    275329        struct xt_node *shnode;
    276 
    277         sha1_state_t sha;
    278         char hash_hex[41];
    279         unsigned char hash[20];
    280         int i;
    281330
    282331        if (!(iq_id   = xt_find_attr(node, "id")) ||
     
    303352                    (port_s = xt_find_attr(shnode, "port")) &&
    304353                    (sscanf(port_s, "%d", &port) == 1)) {
    305                         jabber_streamhost_t *sh = g_new0(jabber_streamhost_t, 1);
    306                         sh->jid = g_strdup(jid);
    307                         sh->host = g_strdup(host);
    308                         sprintf(sh->port, "%u", port);
    309                         shlist = g_slist_append(shlist, sh);
     354                        shlist = g_slist_append(shlist, jabber_streamhost_new(jid, host, port));
    310355                }
    311356                shnode = shnode->next;
     
    317362        }
    318363
    319         /* Let's see if we can find out what this bytestream should be for... */
    320 
    321         for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {
    322                 struct jabber_transfer *tft = tflist->data;
    323                 if ((strcmp(tft->sid, sid) == 0) &&
    324                     (strcmp(tft->ini_jid, ini_jid) == 0) &&
    325                     (strcmp(tft->tgt_jid, tgt_jid) == 0)) {
    326                         tf = tft;
    327                         break;
    328                 }
    329         }
    330 
    331         if (!tf) {
     364        if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) {
    332365                imcb_log(ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid);
    333366                return XT_HANDLED;
     
    339372
    340373        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         }
    352374
    353375        bt = g_new0(struct bs_transfer, 1);
     
    356378        bt->sh = shlist->data;
    357379        bt->phase = BS_PHASE_CONNECT;
    358         bt->pseudoadr = g_strdup(hash_hex);
     380        bt->pseudoaddr = generate_pseudoaddr(sid, ini_jid, tgt_jid);
    359381        tf->streamhandle = bt;
    360382        tf->ft->free = jabber_bs_free_transfer;
     
    451473                        .rsv = 0,
    452474                        .atyp = 0x03,
    453                         .addrlen = strlen(bt->pseudoadr),
     475                        .addrlen = strlen(bt->pseudoaddr),
    454476                        .port = 0
    455477                };
     
    468490
    469491                /* copy hash into connect message */
    470                 memcpy(socks5_connect.address, bt->pseudoadr, socks5_connect.addrlen);
     492                memcpy(socks5_connect.address, bt->pseudoaddr, socks5_connect.addrlen);
    471493
    472494                ASSERTSOCKOP(send(fd, &socks5_connect, sizeof(struct socks5_message), 0), "Sending SOCKS5 Connect");
     
    558580        if (shlist && shlist->next) {
    559581                bt->sh = shlist->next->data;
     582                jabber_bs_remove_events(bt);
    560583                return jabber_bs_recv_handshake(bt, -1, 0);
    561584        }
     
    731754        struct jabber_data *jd = ic->proto_data;
    732755        struct bs_transfer *bt;
    733         GSList *tflist;
    734756        struct xt_node *c;
    735757        char *sid, *jid;
     
    750772        /* Let's see if we can find out what this bytestream should be for... */
    751773
    752         for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {
    753                 struct jabber_transfer *tft = tflist->data;
    754                 if ((strcmp(tft->sid, sid) == 0)) {
    755                         tf = tft;
    756                         break;
    757                 }
    758         }
    759 
    760         if (!tf) {
     774        if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) {
    761775                imcb_log(ic, "WARNING: Received SOCKS5 bytestream reply to unknown request");
    762776                return XT_HANDLED;
     
    776790                /* using a proxy, abort listen */
    777791
    778                 if (tf->watch_in) {
    779                         b_event_remove(tf->watch_in);
    780                         tf->watch_in = 0;
    781                 }
    782 
    783                 if (tf->fd != -1) {
    784                         closesocket(tf->fd);
    785                         tf->fd = -1;
    786                 }
    787 
    788                 if (bt->connect_timeout) {
    789                         b_event_remove(bt->connect_timeout);
    790                         bt->connect_timeout = 0;
    791                 }
     792                jabber_bs_remove_events(bt);
    792793
    793794                GSList *shlist;
     
    838839{
    839840        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         for (tflist = jd->filetransfers; tflist; tflist = g_slist_next(tflist)) {
    849                 struct jabber_transfer *tft = tflist->data;
    850                 if ((strcmp(tft->sid, sid) == 0)) {
    851                         tf = tft;
    852                         break;
    853                 }
    854         }
    855 
    856         if (!tf) {
     848        if (!(tf = get_ft_by_sid(jd->filetransfers, sid))) {
    857849                imcb_log(ic, "WARNING: Received SOCKS5 bytestream activation for unknown stream");
    858850                return XT_HANDLED;
     
    883875        *port++ = '\0';
    884876
    885         sh = g_new0(jabber_streamhost_t, 1);
    886         sh->jid = g_strdup(jid);
    887         sh->host = g_strdup(host);
    888         g_snprintf(sh->port, sizeof(sh->port), "%s", port);
     877        sh = jabber_streamhost_new(jid, host, 0);
     878        strncpy(sh->port, port, sizeof(sh->port));
    889879
    890880        return sh;
     
    910900                if (strcmp(proxy, "<local>") == 0) {
    911901                        if ((tf->fd = ft_listen(&tf->saddr, host, port, jd->fd, FALSE, &errmsg)) != -1) {
    912                                 sh = g_new0(jabber_streamhost_t, 1);
    913                                 sh->jid = g_strdup(tf->ini_jid);
    914                                 sh->host = g_strdup(host);
    915                                 g_snprintf(sh->port, sizeof(sh->port), "%s", port);
     902                                sh = jabber_streamhost_new(tf->ini_jid, host, 0);
     903                                strncpy(sh->port, port, sizeof(sh->port));
    916904                                bt->streamhosts = g_slist_append(bt->streamhosts, sh);
    917905
     
    948936{
    949937        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         }
    965938
    966939        bt = g_new0(struct bs_transfer, 1);
    967940        bt->tf = tf;
    968941        bt->phase = BS_PHASE_CONNECT;
    969         bt->pseudoadr = g_strdup(hash_hex);
     942        bt->pseudoaddr = generate_pseudoaddr(tf->sid, tf->ini_jid, tf->tgt_jid);
    970943        tf->streamhandle = bt;
    971944        tf->ft->free = jabber_bs_free_transfer;
     
    974947        jabber_si_set_proxies(bt);
    975948
    976         ret = jabber_bs_send_request(tf, bt->streamhosts);
    977 
    978         return ret;
     949        return jabber_bs_send_request(tf, bt->streamhosts);
    979950}
    980951
     
    11391110                                               socks5_connect.atyp);
    11401111                }
    1141                 if (!(memcmp(socks5_connect.address, bt->pseudoadr, 40) == 0)) {
     1112                if (!(memcmp(socks5_connect.address, bt->pseudoaddr, 40) == 0)) {
    11421113                        return jabber_bs_abort(bt, "SOCKS5 Connect message contained wrong digest");
    11431114                }
  • protocols/jabber/sasl.c

    r531eabd rb1dc403  
    4242        "https://www.facebook.com/dialog/oauth",
    4343        "https://graph.facebook.com/oauth/access_token",
    44         "http://www.bitlbee.org/main.php/Facebook/oauth2.html",
     44        "https://www.bitlbee.org/main.php/Facebook/oauth2.html",
    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;
     57        int want_oauth = FALSE, want_hipchat = FALSE;
    5858        GString *mechs;
    5959
     
    7575
    7676        want_oauth = set_getbool(&ic->acc->set, "oauth");
     77        want_hipchat = (jd->flags & JFLAG_HIPCHAT);
    7778
    7879        mechs = g_string_new("");
     
    111112
    112113        reply = xt_new_node("auth", NULL, NULL);
    113         xt_add_attr(reply, "xmlns", XMLNS_SASL);
     114        if (!want_hipchat) {
     115                xt_add_attr(reply, "xmlns", XMLNS_SASL);
     116        } else {
     117                xt_add_attr(reply, "xmlns", XMLNS_HIPCHAT);
     118        }
    114119
    115120        if (sup_gtalk && want_oauth) {
     
    143148        } else if (sup_plain) {
    144149                int len;
    145 
    146                 xt_add_attr(reply, "mechanism", "PLAIN");
     150                GString *gs;
     151                char *username;
     152
     153                if (!want_hipchat) {
     154                        xt_add_attr(reply, "mechanism", "PLAIN");
     155                        username = jd->username;
     156                } else {
     157                        username = jd->me;
     158                }
     159
     160                /* set an arbitrary initial size to avoid reallocations */
     161                gs = g_string_sized_new(128);
    147162
    148163                /* With SASL PLAIN in XMPP, the text should be b64(\0user\0pass) */
    149                 len = strlen(jd->username) + strlen(ic->acc->pass) + 2;
    150                 s = g_malloc(len + 1);
    151                 s[0] = 0;
    152                 strcpy(s + 1, jd->username);
    153                 strcpy(s + 2 + strlen(jd->username), ic->acc->pass);
     164                g_string_append_c(gs, '\0');
     165                g_string_append(gs, username);
     166                g_string_append_c(gs, '\0');
     167                g_string_append(gs, ic->acc->pass);
     168                if (want_hipchat) {
     169                        /* Hipchat's variation adds \0resource at the end */
     170                        g_string_append_c(gs, '\0');
     171                        g_string_append(gs, set_getstr(&ic->acc->set, "resource"));
     172                }
     173
     174                len = gs->len;
     175                s = g_string_free(gs, FALSE);
     176
    154177                reply->text = base64_encode((unsigned char *) s, len);
    155178                reply->text_len = strlen(reply->text);
     
    397420                imcb_log(ic, "Authentication finished");
    398421                jd->flags |= JFLAG_AUTHENTICATED | JFLAG_STREAM_RESTART;
     422
     423                if (jd->flags & JFLAG_HIPCHAT) {
     424                        return hipchat_handle_success(ic, node);
     425                }
    399426        } else if (strcmp(node->name, "failure") == 0) {
    400427                imcb_error(ic, "Authentication failure");
  • protocols/msn/Makefile

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

    r531eabd rb1dc403  
    3030int msn_chat_id;
    3131GSList *msn_connections;
    32 GSList *msn_switchboards;
    3332
    3433static char *set_eval_display_name(set_t *set, char *value);
     
    4140        s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;
    4241
    43         s = set_add(&acc->set, "server", MSN_NS_HOST, set_eval_account, acc);
     42        s = set_add(&acc->set, "server", NULL, set_eval_account, acc);
    4443        s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
    4544
     
    4847
    4948        set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
    50         set_add(&acc->set, "switchboard_keepalives", "false", set_eval_bool, acc);
    5149
    5250        acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE |
     
    5856        struct im_connection *ic = imcb_new(acc);
    5957        struct msn_data *md = g_new0(struct msn_data, 1);
     58        char *server = set_getstr(&ic->acc->set, "server");
    6059
    6160        ic->proto_data = md;
    6261        ic->flags |= OPT_PONGS | OPT_PONGED;
     62
     63        if (!server) {
     64                server = "geo.gateway.messenger.live.com";
     65        }
    6366
    6467        if (strchr(acc->user, '@') == NULL) {
     
    7174        md->away_state = msn_away_state_list;
    7275        md->domaintree = g_tree_new(msn_domaintree_cmp);
    73         md->ns->fd = -1;
     76        md->fd = -1;
     77        md->is_http = TRUE;
    7478
    7579        msn_connections = g_slist_prepend(msn_connections, ic);
    7680
    7781        imcb_log(ic, "Connecting");
    78         msn_ns_connect(ic, md->ns,
    79                        set_getstr(&ic->acc->set, "server"),
     82        msn_ns_connect(ic, server,
    8083                       set_getint(&ic->acc->set, "port"));
    8184}
     
    8891
    8992        if (md) {
    90                 /** Disabling MSN ft support for now.
    91                 while( md->filetransfers ) {
    92                         imcb_file_canceled( md->filetransfers->data, "Closing connection" );
    93                 }
    94                 */
    95 
    96                 msn_ns_close(md->ns);
    97 
    98                 while (md->switchboards) {
    99                         msn_sb_destroy(md->switchboards->data);
    100                 }
    101 
    102                 msn_msgq_purge(ic, &md->msgq);
     93                msn_ns_close(md);
     94
    10395                msn_soapq_flush(ic, FALSE);
    10496
     
    112104                while (md->groups) {
    113105                        struct msn_group *mg = md->groups->data;
     106                        md->groups = g_slist_remove(md->groups, mg);
    114107                        g_free(mg->id);
    115108                        g_free(mg->name);
    116109                        g_free(mg);
    117                         md->groups = g_slist_remove(md->groups, mg);
    118110                }
    119111
     
    127119                while (md->grpq) {
    128120                        struct msn_groupadd *ga = md->grpq->data;
     121                        md->grpq = g_slist_remove(md->grpq, ga);
    129122                        g_free(ga->group);
    130123                        g_free(ga->who);
    131124                        g_free(ga);
    132                         md->grpq = g_slist_remove(md->grpq, ga);
    133125                }
    134126
     
    152144{
    153145        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;
    156146
    157147#ifdef DEBUG
    158148        if (strcmp(who, "raw") == 0) {
    159149                msn_ns_write(ic, -1, "%s\r\n", message);
    160         } else
     150                return 0;
     151        }
    161152#endif
    162         if (bd && bd->flags & MSN_BUDDY_FED) {
    163                 msn_ns_sendmessage(ic, bu, message);
    164         } else if ((sb = msn_sb_by_handle(ic, who))) {
    165                 return(msn_sb_sendmessage(sb, message));
    166         } else {
    167                 struct msn_message *m;
    168 
    169                 /* Create a message. We have to arrange a usable switchboard, and send the message later. */
    170                 m = g_new0(struct msn_message, 1);
    171                 m->who = g_strdup(who);
    172                 m->text = g_strdup(message);
    173 
    174                 return msn_sb_write_msg(ic, m);
    175         }
    176 
     153
     154        msn_ns_sendmessage(ic, bu, message);
    177155        return(0);
    178156}
     
    196174static void msn_set_away(struct im_connection *ic, char *state, char *message)
    197175{
    198         char *uux;
    199176        struct msn_data *md = ic->proto_data;
     177        char *nick, *psm, *idle, *statecode, *body, *buf;
    200178
    201179        if (state == NULL) {
     
    205183        }
    206184
    207         if (!msn_ns_write(ic, -1, "CHG %d %s %d:%02d\r\n", ++md->trId, md->away_state->code, MSN_CAP1, MSN_CAP2)) {
    208                 return;
    209         }
    210 
    211         uux = g_markup_printf_escaped("<EndpointData><Capabilities>%d:%02d"
    212                                       "</Capabilities></EndpointData>",
    213                                       MSN_CAP1, MSN_CAP2);
    214         msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux);
    215         g_free(uux);
    216 
    217         uux = g_markup_printf_escaped("<PrivateEndpointData><EpName>%s</EpName>"
    218                                       "<Idle>%s</Idle><ClientType>%d</ClientType>"
    219                                       "<State>%s</State></PrivateEndpointData>",
    220                                       md->uuid,
    221                                       strcmp(md->away_state->code, "IDL") ? "false" : "true",
    222                                       1,  /* ? */
    223                                       md->away_state->code);
    224         msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux);
    225         g_free(uux);
    226 
    227         uux = g_markup_printf_escaped("<Data><DDP></DDP><PSM>%s</PSM>"
    228                                       "<CurrentMedia></CurrentMedia>"
    229                                       "<MachineGuid>%s</MachineGuid></Data>",
    230                                       message ? message : "", md->uuid);
    231         msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux);
    232         g_free(uux);
     185        statecode = (char *) md->away_state->code;
     186        nick = set_getstr(&ic->acc->set, "display_name");
     187        psm = message ? message : "";
     188        idle = (strcmp(statecode, "IDL") == 0) ? "false" : "true";
     189
     190        body = g_markup_printf_escaped(MSN_PUT_USER_BODY,
     191                nick, psm, psm, md->uuid, statecode, md->uuid, idle, statecode,
     192                MSN_CAP1, MSN_CAP2, MSN_CAP1, MSN_CAP2
     193        );
     194
     195        buf = g_strdup_printf(MSN_PUT_HEADERS, ic->acc->user, ic->acc->user, md->uuid,
     196                "/user", "application/user+xml",
     197                strlen(body), body);
     198        msn_ns_write(ic, -1, "PUT %d %zd\r\n%s", ++md->trId, strlen(buf), buf);
     199
     200        g_free(buf);
     201        g_free(body);
    233202}
    234203
     
    256225static void msn_chat_msg(struct groupchat *c, char *message, int flags)
    257226{
    258         struct msn_switchboard *sb = msn_sb_by_chat(c);
    259 
    260         if (sb) {
    261                 msn_sb_sendmessage(sb, message);
    262         }
    263         /* FIXME: Error handling (although this can't happen unless something's
    264            already severely broken) disappeared here! */
     227        /* TODO: groupchats*/
    265228}
    266229
    267230static void msn_chat_invite(struct groupchat *c, char *who, char *message)
    268231{
    269         struct msn_switchboard *sb = msn_sb_by_chat(c);
    270 
    271         if (sb) {
    272                 msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, who);
    273         }
     232        /* TODO: groupchats*/
    274233}
    275234
    276235static void msn_chat_leave(struct groupchat *c)
    277236{
    278         struct msn_switchboard *sb = msn_sb_by_chat(c);
    279 
    280         if (sb) {
    281                 msn_sb_write(sb, "OUT\r\n");
    282         }
     237        /* TODO: groupchats*/
    283238}
    284239
    285240static struct groupchat *msn_chat_with(struct im_connection *ic, char *who)
    286241{
    287         struct msn_switchboard *sb;
     242        /* TODO: groupchats*/
    288243        struct groupchat *c = imcb_chat_new(ic, who);
    289 
    290         if ((sb = msn_sb_by_handle(ic, who))) {
    291                 debug("Converting existing switchboard to %s to a groupchat", who);
    292                 return msn_sb_to_chat(sb);
    293         } else {
    294                 struct msn_message *m;
    295 
    296                 /* Create a magic message. This is quite hackish, but who cares? :-P */
    297                 m = g_new0(struct msn_message, 1);
    298                 m->who = g_strdup(who);
    299                 m->text = g_strdup(GROUPCHAT_SWITCHBOARD_MESSAGE);
    300 
    301                 msn_sb_write_msg(ic, m);
    302 
    303                 return c;
    304         }
     244        return c;
    305245}
    306246
     
    322262static void msn_add_deny(struct im_connection *ic, char *who)
    323263{
    324         struct msn_switchboard *sb;
    325 
    326264        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         }
    332265}
    333266
     
    462395        ret->buddy_action = msn_buddy_action;
    463396
    464         //ret->transfer_request = msn_ftp_transfer_request;
    465 
    466397        register_protocol(ret);
    467398}
  • protocols/msn/msn.h

    r531eabd rb1dc403  
    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"
    3534
    3635#ifdef DEBUG_MSN
     
    6059#define MSNP11_PROD_KEY "C1BX{V4W}Q3*10SM"
    6160#define MSNP11_PROD_ID  "PROD0120PW!CCV9@"
    62 #define MSNP_VER        "MSNP18"
     61#define MSNP_VER        "MSNP21"
    6362#define MSNP_BUILD      "14.0.8117.416"
    6463
     
    6867#define MSN_CAP2        0x0000
    6968
    70 #define MSN_MESSAGE_HEADERS "MIME-Version: 1.0\r\n" \
     69#define MSN_BASE_HEADERS \
     70        "Routing: 1.0\r\n" \
     71        "To: 1:%s\r\n" \
     72        "From: 1:%s;epid={%s}\r\n" \
     73        "\r\n" \
     74        "Reliability: 1.0\r\n" \
     75        "\r\n"
     76
     77#define MSN_MESSAGE_HEADERS MSN_BASE_HEADERS \
     78        "Messaging: 2.0\r\n" \
     79        "Message-Type: Text\r\n" \
     80        "Content-Length: %zd\r\n" \
    7181        "Content-Type: text/plain; charset=UTF-8\r\n" \
    72         "User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \
    73         "X-MMS-IM-Format: FN=MS%20Shell%20Dlg; EF=; CO=0; CS=0; PF=0\r\n" \
    74         "\r\n"
     82        "X-MMS-IM-Format: FN=Segoe%%20UI; EF=; CO=0; CS=0; PF=0\r\n" \
     83        "\r\n" \
     84        "%s"
     85
     86#define MSN_PUT_HEADERS MSN_BASE_HEADERS \
     87        "Publication: 1.0\r\n" \
     88        "Uri: %s\r\n" \
     89        "Content-Type: %s\r\n" \
     90        "Content-Length: %zd\r\n" \
     91        "\r\n" \
     92        "%s"
     93
     94#define MSN_PUT_USER_BODY \
     95        "<user>" \
     96        "<s n=\"PE\"><UserTileLocation></UserTileLocation><FriendlyName>%s</FriendlyName><PSM>%s</PSM><DDP></DDP>" \
     97        "<Scene></Scene><ASN></ASN><ColorScheme>-3</ColorScheme><BDG></BDG><RUM>%s</RUM><RUL></RUL><RLT>0</RLT>" \
     98        "<RID></RID><SUL></SUL><MachineGuid>%s</MachineGuid></s>" \
     99        "<s n=\"IM\"><Status>%s</Status><CurrentMedia></CurrentMedia></s>" \
     100        "<sep n=\"PD\"><ClientType>1</ClientType><EpName>%s</EpName><Idle>%s</Idle><State>%s</State></sep>" \
     101        "<sep n=\"PE\"><VER>BitlBee:" BITLBEE_VERSION "</VER><TYP>1</TYP><Capabilities>%d:%d</Capabilities></sep>" \
     102        "<sep n=\"IM\"><Capabilities>%d:%d</Capabilities></sep>" \
     103        "</user>"
    75104
    76105#define MSN_TYPING_HEADERS "MIME-Version: 1.0\r\n" \
     
    84113        "ID: 1\r\n" \
    85114        "\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"
    90115
    91116#define PROFILE_URL "http://members.msn.com/"
     
    99124} msn_flags_t;
    100125
    101 struct msn_handler_data {
     126struct 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
     148struct msn_data {
    102149        int fd, inpa;
    103150        int rxlen;
     
    107154        char *cmd_text;
    108155
    109         /* Either ic or sb */
    110         gpointer data;
    111 
    112         int (*exec_command) (struct msn_handler_data *handler, char **cmd, int count);
    113         int (*exec_message) (struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int count);
    114 };
    115 
    116 struct msn_data {
    117156        struct im_connection *ic;
    118157
    119         struct msn_handler_data ns[1];
    120158        msn_flags_t flags;
    121159
     
    126164
    127165        GSList *msgq, *grpq, *soapq;
    128         GSList *switchboards;
    129         int sb_failures;
    130         time_t first_sb_failure;
    131166
    132167        const struct msn_away_state *away_state;
     
    139174        GTree *domaintree;
    140175        int adl_todo;
    141 };
    142 
    143 struct msn_switchboard {
    144         struct im_connection *ic;
    145 
    146         /* The following two are also in the handler. TODO: Clean up. */
    147         int fd;
    148         gint inp;
    149         struct msn_handler_data *handler;
    150         gint keepalive;
    151 
    152         int trId;
    153         int ready;
    154 
    155         int session;
    156         char *key;
    157 
    158         GSList *msgq;
    159         char *who;
    160         struct groupchat *chat;
     176
     177        gboolean is_http;
     178        struct msn_gw *gw;
    161179};
    162180
     
    205223#define STATUS_FATAL            1
    206224#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). */
    209225
    210226extern int msn_chat_id;
     
    218234   before doing *anything* else. */
    219235extern GSList *msn_connections;
    220 extern GSList *msn_switchboards;
    221236
    222237/* ns.c */
    223238int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) G_GNUC_PRINTF(3, 4);
    224 gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port);
    225 void msn_ns_close(struct msn_handler_data *handler);
     239gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port);
     240void msn_ns_close(struct msn_data *handler);
    226241void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error);
    227242void msn_auth_got_contact_list(struct im_connection *ic);
    228243int msn_ns_finish_login(struct im_connection *ic);
    229244int msn_ns_sendmessage(struct im_connection *ic, struct bee_user *bu, const char *text);
    230 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq);
     245int msn_ns_command(struct msn_data *md, char **cmd, int num_parts);
     246int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts);
    231247
    232248/* msn_util.c */
     
    235251int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group);
    236252void msn_buddy_ask(bee_user_t *bu);
    237 char **msn_linesplit(char *line);
    238 int msn_handler(struct msn_handler_data *h);
    239 void msn_msgq_purge(struct im_connection *ic, GSList **list);
     253void msn_queue_feed(struct msn_data *h, char *bytes, int st);
     254int msn_handler(struct msn_data *h);
    240255char *msn_p11_challenge(char *challenge);
    241256gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_);
     
    251266const struct msn_status_code *msn_status_by_number(int number);
    252267
    253 /* sb.c */
    254 int msn_sb_write(struct msn_switchboard *sb, const char *fmt, ...) G_GNUC_PRINTF(2, 3);;
    255 struct msn_switchboard *msn_sb_create(struct im_connection *ic, char *host, int port, char *key, int session);
    256 struct msn_switchboard *msn_sb_by_handle(struct im_connection *ic, const char *handle);
    257 struct msn_switchboard *msn_sb_by_chat(struct groupchat *c);
    258 struct msn_switchboard *msn_sb_spare(struct im_connection *ic);
    259 int msn_sb_sendmessage(struct msn_switchboard *sb, char *text);
    260 struct groupchat *msn_sb_to_chat(struct msn_switchboard *sb);
    261 void msn_sb_destroy(struct msn_switchboard *sb);
    262 gboolean msn_sb_connected(gpointer data, gint source, b_input_condition cond);
    263 int msn_sb_write_msg(struct im_connection *ic, struct msn_message *m);
    264 void msn_sb_start_keepalives(struct msn_switchboard *sb, gboolean initial);
    265 void msn_sb_stop_keepalives(struct msn_switchboard *sb);
     268/* gw.c */
     269struct msn_gw *msn_gw_new(struct im_connection *ic);
     270void msn_gw_free(struct msn_gw *gw);
     271void msn_gw_open(struct msn_gw *gw);
     272ssize_t msn_gw_read(struct msn_gw *gw, char **buf);
     273void msn_gw_write(struct msn_gw *gw, char *buf, size_t len);
    266274
    267275#endif //_MSN_H
  • protocols/msn/msn_util.c

    r531eabd rb1dc403  
    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
    9957
    10058        if (!((bu = bee_user_by_handle(ic->bee, ic, who)) ||
     
    13290
    13391        *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
    14592
    14693        if (!(bu = bee_user_by_handle(ic->bee, ic, who)) ||
     
    174121};
    175122
    176 static void msn_buddy_ask_yes(void *data)
     123static void msn_buddy_ask_free(void *data)
    177124{
    178125        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);
    183126
    184127        g_free(bla->handle);
     
    187130}
    188131
     132static void msn_buddy_ask_yes(void *data)
     133{
     134        struct msn_buddy_ask_data *bla = data;
     135
     136        msn_buddy_list_add(bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL);
     137
     138        imcb_ask_add(bla->ic, bla->handle, NULL);
     139
     140        msn_buddy_ask_free(bla);
     141}
     142
    189143static void msn_buddy_ask_no(void *data)
    190144{
     
    193147        msn_buddy_list_add(bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL);
    194148
    195         g_free(bla->handle);
    196         g_free(bla->realname);
    197         g_free(bla);
     149        msn_buddy_ask_free(bla);
    198150}
    199151
     
    216168                   "The user %s (%s) wants to add you to his/her buddy list.",
    217169                   bu->handle, bu->fullname);
    218         imcb_ask(bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no);
    219 }
    220 
    221 /* *NOT* thread-safe, but that's not a problem for now... */
    222 char **msn_linesplit(char *line)
    223 {
    224         static char **ret = NULL;
    225         static int size = 3;
    226         int i, n = 0;
    227 
    228         if (ret == NULL) {
    229                 ret = g_new0(char*, size);
    230         }
    231 
    232         for (i = 0; line[i] && line[i] == ' '; i++) {
    233                 ;
    234         }
    235         if (line[i]) {
    236                 ret[n++] = line + i;
    237                 for (i++; line[i]; i++) {
    238                         if (line[i] == ' ') {
    239                                 line[i] = 0;
    240                         } else if (line[i] != ' ' && !line[i - 1]) {
    241                                 ret[n++] = line + i;
    242                         }
    243 
    244                         if (n >= size) {
    245                                 ret = g_renew(char*, ret, size += 2);
    246                         }
    247                 }
    248         }
    249         ret[n] = NULL;
    250 
    251         return(ret);
     170
     171        imcb_ask_with_free(bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no, msn_buddy_ask_free);
     172}
     173
     174void 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        }
    252185}
    253186
     
    260193                   1: OK */
    261194
    262 int msn_handler(struct msn_handler_data *h)
    263 {
    264         int st;
    265 
    266         h->rxq = g_renew(char, h->rxq, h->rxlen + 1024);
    267         st = read(h->fd, h->rxq + h->rxlen, 1024);
    268         h->rxlen += st;
    269 
    270         if (st <= 0) {
    271                 return(-1);
    272         }
    273 
    274         if (getenv("BITLBEE_DEBUG")) {
    275                 write(2, "->C:", 4);
    276                 write(2, h->rxq + h->rxlen - st, st);
    277         }
     195int msn_handler(struct msn_data *h)
     196{
     197        int st = 1;
    278198
    279199        while (st) {
     
    287207
    288208                                        cmd_text = g_strndup(h->rxq, i);
    289                                         cmd = msn_linesplit(cmd_text);
    290                                         for (count = 0; cmd[count]; count++) {
    291                                                 ;
    292                                         }
    293                                         st = h->exec_command(h, cmd, count);
     209                                        cmd = g_strsplit_set(cmd_text, " ", -1);
     210                                        count = g_strv_length(cmd);
     211
     212                                        st = msn_ns_command(h, cmd, count);
     213
     214                                        g_strfreev(cmd);
    294215                                        g_free(cmd_text);
    295216
     
    314235                        /* If we reached the end of the buffer, there's still an incomplete command there.
    315236                           Return and wait for more data. */
    316                         if (i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') {
     237                        if (i && i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') {
    317238                                break;
    318239                        }
     
    327248
    328249                        msg = g_strndup(h->rxq, h->msglen);
    329                         cmd = msn_linesplit(h->cmd_text);
    330                         for (count = 0; cmd[count]; count++) {
    331                                 ;
    332                         }
    333 
    334                         st = h->exec_message(h, msg, h->msglen, cmd, count);
     250
     251                        cmd = g_strsplit_set(h->cmd_text, " ", -1);
     252                        count = g_strv_length(cmd);
     253
     254                        st = msn_ns_message(h, msg, h->msglen, cmd, count);
     255
     256                        g_strfreev(cmd);
    335257                        g_free(msg);
    336258                        g_free(h->cmd_text);
     
    366288}
    367289
    368 void msn_msgq_purge(struct im_connection *ic, GSList **list)
    369 {
    370         struct msn_message *m;
    371         GString *ret;
    372         GSList *l;
    373         int n = 0;
    374 
    375         l = *list;
    376         if (l == NULL) {
    377                 return;
    378         }
    379 
    380         m = l->data;
    381         ret = g_string_sized_new(1024);
    382         g_string_printf(ret, "Warning: Cleaning up MSN (switchboard) connection with unsent "
    383                         "messages to %s:", m->who ? m->who : "unknown recipient");
    384 
    385         while (l) {
    386                 m = l->data;
    387 
    388                 if (strncmp(m->text, "\r\r\r", 3) != 0) {
    389                         g_string_append_printf(ret, "\n%s", m->text);
    390                         n++;
    391                 }
    392 
    393                 g_free(m->who);
    394                 g_free(m->text);
    395                 g_free(m);
    396 
    397                 l = l->next;
    398         }
    399         g_slist_free(*list);
    400         *list = NULL;
    401 
    402         if (n > 0) {
    403                 imcb_log(ic, "%s", ret->str);
    404         }
    405         g_string_free(ret, TRUE);
    406 }
    407 
    408290/* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */
    409291char *msn_p11_challenge(char *challenge)
     
    529411int msn_ns_set_display_name(struct im_connection *ic, const char *value)
    530412{
    531         struct msn_data *md = ic->proto_data;
    532         char fn[strlen(value) * 3 + 1];
    533 
    534         strcpy(fn, value);
    535         http_encode(fn);
    536 
    537         /* Note: We don't actually know if the server accepted the new name,
    538            and won't give proper feedback yet if it doesn't. */
    539         return msn_ns_write(ic, -1, "PRP %d MFN %s\r\n", ++md->trId, fn);
     413        // TODO, implement this through msn_set_away's method
     414        return 1;
    540415}
    541416
  • protocols/msn/ns.c

    r531eabd rb1dc403  
    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);
    37 static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts);
    38 static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts);
    3937
    4038static void msn_ns_send_adl_start(struct im_connection *ic);
    4139static void msn_ns_send_adl(struct im_connection *ic);
     40static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd);
     41static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action);
     42static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put);
    4243
    4344int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...)
     
    5455
    5556        if (fd < 0) {
    56                 fd = md->ns->fd;
     57                fd = md->fd;
    5758        }
    5859
    5960        if (getenv("BITLBEE_DEBUG")) {
    60                 fprintf(stderr, "->NS%d:%s\n", fd, out);
     61                fprintf(stderr, "\x1b[91m>>>[NS%d] %s\n\x1b[97m", fd, out);
    6162        }
    6263
    6364        len = strlen(out);
    64         st = write(fd, out, len);
     65
     66        if (md->is_http) {
     67                st = len;
     68                msn_gw_write(md->gw, out, len);
     69        } else {
     70                st = write(fd, out, len);
     71        }
     72
    6573        g_free(out);
    6674        if (st != len) {
     
    7381}
    7482
    75 gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port)
    76 {
    77         if (handler->fd >= 0) {
    78                 closesocket(handler->fd);
    79         }
    80 
    81         handler->exec_command = msn_ns_command;
    82         handler->exec_message = msn_ns_message;
    83         handler->data = ic;
    84         handler->fd = proxy_connect(host, port, msn_ns_connected, handler);
    85         if (handler->fd < 0) {
     83gboolean 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
     107static 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) {
    86113                imcb_error(ic, "Could not connect to server");
    87114                imc_logout(ic, TRUE);
     
    89116        }
    90117
    91         return TRUE;
    92 }
    93 
    94 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond)
    95 {
    96         struct msn_handler_data *handler = data;
    97         struct im_connection *ic = handler->data;
    98         struct msn_data *md;
    99 
    100         if (!g_slist_find(msn_connections, ic)) {
    101                 return FALSE;
    102         }
    103 
    104         md = ic->proto_data;
    105 
    106         if (source == -1) {
    107                 imcb_error(ic, "Could not connect to server");
    108                 imc_logout(ic, TRUE);
    109                 return FALSE;
    110         }
    111 
    112         g_free(handler->rxq);
    113         handler->rxlen = 0;
    114         handler->rxq = g_new0(char, 1);
     118        g_free(md->rxq);
     119        md->rxlen = 0;
     120        md->rxq = g_new0(char, 1);
    115121
    116122        if (md->uuid == NULL) {
     
    130136
    131137        if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER)) {
    132                 handler->inpa = b_input_add(handler->fd, B_EV_IO_READ, msn_ns_callback, handler);
     138                if (!md->is_http) {
     139                        md->inpa = b_input_add(md->fd, B_EV_IO_READ, msn_ns_callback, md);
     140                }
    133141                imcb_log(ic, "Connected to server, waiting for reply");
    134142        }
     
    137145}
    138146
    139 void msn_ns_close(struct msn_handler_data *handler)
    140 {
    141         if (handler->fd >= 0) {
    142                 closesocket(handler->fd);
    143                 b_event_remove(handler->inpa);
    144         }
    145 
    146         handler->fd = handler->inpa = -1;
    147         g_free(handler->rxq);
    148         g_free(handler->cmd_text);
    149 
    150         handler->rxlen = 0;
    151         handler->rxq = NULL;
    152         handler->cmd_text = NULL;
     147void 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;
    153164}
    154165
    155166static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond)
    156167{
    157         struct msn_handler_data *handler = data;
    158         struct im_connection *ic = handler->data;
    159 
    160         if (msn_handler(handler) == -1) {  /* Don't do this on ret == 0, it's already done then. */
     168        struct msn_data *md = data;
     169        struct im_connection *ic = md->ic;
     170        char *bytes;
     171        int st;
     172
     173        if (md->is_http) {
     174                st = msn_gw_read(md->gw, &bytes);
     175        } else {
     176                bytes = g_malloc(1024);
     177                st = read(md->fd, bytes, 1024);
     178        }
     179
     180        if (st <= 0) {
    161181                imcb_error(ic, "Error while reading from server");
    162182                imc_logout(ic, TRUE);
    163 
    164183                return FALSE;
    165         } else {
    166                 return TRUE;
    167         }
    168 }
    169 
    170 static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts)
    171 {
    172         struct im_connection *ic = handler->data;
    173         struct msn_data *md = ic->proto_data;
     184        }
     185
     186        msn_queue_feed(md, bytes, st);
     187
     188        g_free(bytes);
     189
     190        /* Ignore ret == 0, it's already disconnected then. */
     191        msn_handler(md);
     192
     193        return TRUE;
     194       
     195}
     196
     197int msn_ns_command(struct msn_data *md, char **cmd, int num_parts)
     198{
     199        struct im_connection *ic = md->ic;
    174200
    175201        if (num_parts == 0) {
     
    185211                }
    186212
    187                 return(msn_ns_write(ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",
     213                return(msn_ns_write(ic, md->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s VmVyc2lvbjogMQ0KWGZyQ291bnQ6IDINClhmclNlbnRVVENUaW1lOiA2MzU2MTQ3OTU5NzgzOTAwMDANCklzR2VvWGZyOiB0cnVlDQo=\r\n",
    188214                                    ++md->trId, ic->acc->user));
    189215        } else if (strcmp(cmd[0], "CVR") == 0) {
    190216                /* We don't give a damn about the information we just received */
    191                 return msn_ns_write(ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);
     217                return msn_ns_write(ic, md->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);
    192218        } else if (strcmp(cmd[0], "XFR") == 0) {
    193219                char *server;
     
    195221
    196222                if (num_parts >= 6 && strcmp(cmd[2], "NS") == 0) {
    197                         b_event_remove(handler->inpa);
    198                         handler->inpa = -1;
     223                        b_event_remove(md->inpa);
     224                        md->inpa = -1;
    199225
    200226                        server = strchr(cmd[3], ':');
     
    209235
    210236                        imcb_log(ic, "Transferring to other server");
    211                         return msn_ns_connect(ic, handler, server, port);
    212                 } else if (num_parts >= 6 && strcmp(cmd[2], "SB") == 0) {
    213                         struct msn_switchboard *sb;
    214 
    215                         server = strchr(cmd[3], ':');
    216                         if (!server) {
    217                                 imcb_error(ic, "Syntax error");
    218                                 imc_logout(ic, TRUE);
    219                                 return(0);
    220                         }
    221                         *server = 0;
    222                         port = atoi(server + 1);
    223                         server = cmd[3];
    224 
    225                         if (strcmp(cmd[4], "CKI") != 0) {
    226                                 imcb_error(ic, "Unknown authentication method for switchboard");
    227                                 imc_logout(ic, TRUE);
    228                                 return(0);
    229                         }
    230 
    231                         debug("Connecting to a new switchboard with key %s", cmd[5]);
    232 
    233                         if ((sb = msn_sb_create(ic, server, port, cmd[5], MSN_SB_NEW)) == NULL) {
    234                                 /* Although this isn't strictly fatal for the NS connection, it's
    235                                    definitely something serious (we ran out of file descriptors?). */
    236                                 imcb_error(ic, "Could not create new switchboard");
    237                                 imc_logout(ic, TRUE);
    238                                 return(0);
    239                         }
    240 
    241                         if (md->msgq) {
    242                                 struct msn_message *m = md->msgq->data;
    243                                 GSList *l;
    244 
    245                                 sb->who = g_strdup(m->who);
    246 
    247                                 /* Move all the messages to the first user in the message
    248                                    queue to the switchboard message queue. */
    249                                 l = md->msgq;
    250                                 while (l) {
    251                                         m = l->data;
    252                                         l = l->next;
    253                                         if (strcmp(m->who, sb->who) == 0) {
    254                                                 sb->msgq = g_slist_append(sb->msgq, m);
    255                                                 md->msgq = g_slist_remove(md->msgq, m);
    256                                         }
    257                                 }
    258                         }
     237                        return msn_ns_connect(ic, server, port);
    259238                } else {
    260239                        imcb_error(ic, "Syntax error");
     
    290269                }
    291270
    292                 handler->msglen = atoi(cmd[3]);
    293 
    294                 if (handler->msglen <= 0) {
     271                md->msglen = atoi(cmd[3]);
     272
     273                if (md->msglen <= 0) {
    295274                        imcb_error(ic, "Syntax error");
    296275                        imc_logout(ic, TRUE);
    297276                        return(0);
    298277                }
    299         } else if (strcmp(cmd[0], "BLP") == 0) {
    300                 msn_ns_send_adl_start(ic);
    301                 return msn_ns_finish_login(ic);
    302278        } else if (strcmp(cmd[0], "ADL") == 0) {
    303279                if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) {
     
    305281                        return msn_ns_finish_login(ic);
    306282                } else if (num_parts >= 3) {
    307                         handler->msglen = atoi(cmd[2]);
    308                 }
    309         } else if (strcmp(cmd[0], "PRP") == 0) {
    310                 imcb_connected(ic);
     283                        md->msglen = atoi(cmd[2]);
     284                }
    311285        } else if (strcmp(cmd[0], "CHL") == 0) {
    312286                char *resp;
     
    326300                g_free(resp);
    327301                return st;
    328         } else if (strcmp(cmd[0], "ILN") == 0 || strcmp(cmd[0], "NLN") == 0) {
    329                 const struct msn_away_state *st;
    330                 const char *handle;
    331                 int cap = 0;
    332 
    333                 if (num_parts < 6) {
    334                         imcb_error(ic, "Syntax error");
    335                         imc_logout(ic, TRUE);
    336                         return(0);
    337                 }
    338                 /* ILN and NLN are more or less the same, except ILN has a trId
    339                    at the start, and NLN has a capability field at the end.
    340                    Does ILN still exist BTW? */
    341                 if (cmd[0][1] == 'I') {
    342                         cmd++;
    343                 } else {
    344                         cap = atoi(cmd[4]);
    345                 }
    346 
    347                 handle = msn_normalize_handle(cmd[2]);
    348                 if (strcmp(handle, ic->acc->user) == 0) {
    349                         return 1; /* That's me! */
    350 
    351                 }
    352                 http_decode(cmd[3]);
    353                 imcb_rename_buddy(ic, handle, cmd[3]);
    354 
    355                 st = msn_away_state_by_code(cmd[1]);
    356                 if (!st) {
    357                         /* FIXME: Warn/Bomb about unknown away state? */
    358                         st = msn_away_state_list + 1;
    359                 }
    360 
    361                 imcb_buddy_status(ic, handle, OPT_LOGGED_IN |
    362                                   (st != msn_away_state_list ? OPT_AWAY : 0) |
    363                                   (cap & 1 ? OPT_MOBILE : 0),
    364                                   st->name, NULL);
    365 
    366                 msn_sb_stop_keepalives(msn_sb_by_handle(ic, handle));
    367         } else if (strcmp(cmd[0], "FLN") == 0) {
    368                 const char *handle;
    369 
    370                 if (cmd[1] == NULL) {
    371                         return 1;
    372                 }
    373 
    374                 handle = msn_normalize_handle(cmd[1]);
    375                 imcb_buddy_status(ic, handle, 0, NULL, NULL);
    376                 msn_sb_start_keepalives(msn_sb_by_handle(ic, handle), TRUE);
    377         } else if (strcmp(cmd[0], "RNG") == 0) {
    378                 struct msn_switchboard *sb;
    379                 char *server;
    380                 int session, port;
    381 
    382                 if (num_parts < 7) {
    383                         imcb_error(ic, "Syntax error");
    384                         imc_logout(ic, TRUE);
    385                         return(0);
    386                 }
    387 
    388                 session = atoi(cmd[1]);
    389 
    390                 server = strchr(cmd[2], ':');
    391                 if (!server) {
    392                         imcb_error(ic, "Syntax error");
    393                         imc_logout(ic, TRUE);
    394                         return(0);
    395                 }
    396                 *server = 0;
    397                 port = atoi(server + 1);
    398                 server = cmd[2];
    399 
    400                 if (strcmp(cmd[3], "CKI") != 0) {
    401                         imcb_error(ic, "Unknown authentication method for switchboard");
    402                         imc_logout(ic, TRUE);
    403                         return(0);
    404                 }
    405 
    406                 debug("Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4]);
    407 
    408                 if ((sb = msn_sb_create(ic, server, port, cmd[4], session)) == NULL) {
    409                         /* Although this isn't strictly fatal for the NS connection, it's
    410                            definitely something serious (we ran out of file descriptors?). */
    411                         imcb_error(ic, "Could not create new switchboard");
    412                         imc_logout(ic, TRUE);
    413                         return(0);
    414                 } else {
    415                         sb->who = g_strdup(msn_normalize_handle(cmd[5]));
    416                 }
     302        } else if (strcmp(cmd[0], "QRY") == 0) {
     303                /* CONGRATULATIONS */
    417304        } else if (strcmp(cmd[0], "OUT") == 0) {
    418                 int allow_reconnect = TRUE;
    419 
    420                 if (cmd[1] && strcmp(cmd[1], "OTH") == 0) {
    421                         imcb_error(ic, "Someone else logged in with your account");
    422                         allow_reconnect = FALSE;
    423                 } else if (cmd[1] && strcmp(cmd[1], "SSD") == 0) {
    424                         imcb_error(ic, "Terminating session because of server shutdown");
    425                 } else {
    426                         imcb_error(ic, "Session terminated by remote server (%s)",
    427                                    cmd[1] ? cmd[1] : "reason unknown)");
    428                 }
    429 
    430                 imc_logout(ic, allow_reconnect);
     305                imcb_error(ic, "Session terminated by remote server (%s)", cmd[1] ? cmd[1] : "reason unknown");
     306                imc_logout(ic, TRUE);
    431307                return(0);
    432         } else if (strcmp(cmd[0], "IPG") == 0) {
    433                 imcb_error(ic, "Received IPG command, we don't handle them yet.");
    434 
    435                 handler->msglen = atoi(cmd[1]);
    436 
    437                 if (handler->msglen <= 0) {
    438                         imcb_error(ic, "Syntax error");
    439                         imc_logout(ic, TRUE);
    440                         return(0);
    441                 }
    442         }
    443 #if 0
    444         else if (strcmp(cmd[0], "ADG") == 0) {
    445                 char *group = g_strdup(cmd[3]);
    446                 int groupnum, i;
    447                 GSList *l, *next;
    448 
    449                 http_decode(group);
    450                 if (sscanf(cmd[4], "%d", &groupnum) == 1) {
    451                         if (groupnum >= md->groupcount) {
    452                                 md->grouplist = g_renew(char *, md->grouplist, groupnum + 1);
    453                                 for (i = md->groupcount; i <= groupnum; i++) {
    454                                         md->grouplist[i] = NULL;
    455                                 }
    456                                 md->groupcount = groupnum + 1;
    457                         }
    458                         g_free(md->grouplist[groupnum]);
    459                         md->grouplist[groupnum] = group;
    460                 } else {
    461                         /* Shouldn't happen, but if it does, give up on the group. */
    462                         g_free(group);
    463                         imcb_error(ic, "Syntax error");
    464                         imc_logout(ic, TRUE);
    465                         return 0;
    466                 }
    467 
    468                 for (l = md->grpq; l; l = next) {
    469                         struct msn_groupadd *ga = l->data;
    470                         next = l->next;
    471                         if (g_strcasecmp(ga->group, group) == 0) {
    472                                 if (!msn_buddy_list_add(ic, "FL", ga->who, ga->who, group)) {
    473                                         return 0;
    474                                 }
    475 
    476                                 g_free(ga->group);
    477                                 g_free(ga->who);
    478                                 g_free(ga);
    479                                 md->grpq = g_slist_remove(md->grpq, ga);
    480                         }
    481                 }
    482         }
    483 #endif
    484         else if (strcmp(cmd[0], "GCF") == 0) {
     308        } else if (strcmp(cmd[0], "GCF") == 0) {
    485309                /* Coming up is cmd[2] bytes of stuff we're supposed to
    486310                   censore. Meh. */
    487                 handler->msglen = atoi(cmd[2]);
    488         } else if (strcmp(cmd[0], "UBX") == 0) {
    489                 /* Status message. */
     311                md->msglen = atoi(cmd[2]);
     312        } else if ((strcmp(cmd[0], "NFY") == 0) || (strcmp(cmd[0], "SDG") == 0)) {
    490313                if (num_parts >= 3) {
    491                         handler->msglen = atoi(cmd[2]);
     314                        md->msglen = atoi(cmd[2]);
     315                }
     316        } else if (strcmp(cmd[0], "PUT") == 0) {
     317                if (num_parts >= 4) {
     318                        md->msglen = atoi(cmd[3]);
    492319                }
    493320        } else if (strcmp(cmd[0], "NOT") == 0) {
    494                 /* Some kind of notification, poorly documented but
    495                    apparently used to announce address book changes. */
    496321                if (num_parts >= 2) {
    497                         handler->msglen = atoi(cmd[1]);
    498                 }
    499         } else if (strcmp(cmd[0], "UBM") == 0) {
    500                 if (num_parts >= 7) {
    501                         handler->msglen = atoi(cmd[6]);
     322                        md->msglen = atoi(cmd[1]);
    502323                }
    503324        } else if (strcmp(cmd[0], "QNG") == 0) {
     
    516337                /* Oh yes, errors can have payloads too now. Discard them for now. */
    517338                if (num_parts >= 3) {
    518                         handler->msglen = atoi(cmd[2]);
     339                        md->msglen = atoi(cmd[2]);
    519340                }
    520341        } else {
    521                 /* debug( "Received unknown command from main server: %s", cmd[0] ); */
     342                imcb_error(ic, "Received unknown command from main server: %s", cmd[0]);
    522343        }
    523344
     
    525346}
    526347
    527 static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts)
    528 {
    529         struct im_connection *ic = handler->data;
     348int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts)
     349{
     350        struct im_connection *ic = md->ic;
    530351        char *body;
    531352        int blen = 0;
     
    598419                                }
    599420                        } else if (g_strncasecmp(ct, "text/x-msmsgsactivemailnotification", 35) == 0) {
    600                         } else if (g_strncasecmp(ct, "text/x-msmsgsinitialmdatanotification", 37) == 0 ||
    601                                    g_strncasecmp(ct, "text/x-msmsgsoimnotification", 28) == 0) {
    602                                 /* We received an offline message. Or at least notification
    603                                    that there is one waiting for us. Fetching the message(s)
    604                                    and purging them from the server is a lot of SOAPy work
    605                                    not worth doing IMHO. Also I thought it was possible to
    606                                    have the notification server send them directly, I was
    607                                    pretty sure I saw Pidgin do it..
    608 
    609                                    At least give a notification for now, seems like a
    610                                    reasonable thing to do. Only problem is, they'll keep
    611                                    coming back at login time until you read them using a
    612                                    different client. :-( */
    613 
    614                                 char *xml = get_rfc822_header(body, "Mail-Data:", blen);
    615                                 struct xt_node *md, *m;
    616 
    617                                 if (!xml) {
    618                                         return 1;
    619                                 }
    620                                 md = xt_from_string(xml, 0);
    621                                 if (!md) {
    622                                         return 1;
    623                                 }
    624 
    625                                 for (m = md->children; (m = xt_find_node(m, "M")); m = m->next) {
    626                                         struct xt_node *e = xt_find_node(m->children, "E");
    627                                         struct xt_node *rt = xt_find_node(m->children, "RT");
    628                                         struct tm tp;
    629                                         time_t msgtime = 0;
    630 
    631                                         if (!e || !e->text) {
    632                                                 continue;
    633                                         }
    634 
    635                                         memset(&tp, 0, sizeof(tp));
    636                                         if (rt && rt->text &&
    637                                             sscanf(rt->text, "%4d-%2d-%2dT%2d:%2d:%2d.",
    638                                                    &tp.tm_year, &tp.tm_mon, &tp.tm_mday,
    639                                                    &tp.tm_hour, &tp.tm_min, &tp.tm_sec) == 6) {
    640                                                 tp.tm_year -= 1900;
    641                                                 tp.tm_mon--;
    642                                                 msgtime = mktime_utc(&tp);
    643 
    644                                         }
    645                                         imcb_buddy_msg(ic, e->text,
    646                                                        "<< \002BitlBee\002 - Received offline message. BitlBee can't show these. >>", 0,
    647                                                        msgtime);
    648                                 }
    649 
    650                                 g_free(xml);
    651                                 xt_free_node(md);
     421                                /* Notification that a message has been read... Ignore it */
    652422                        } else {
    653423                                debug("Can't handle %s packet from notification server", ct);
     
    656426                        g_free(ct);
    657427                }
    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);
    670428        } else if (strcmp(cmd[0], "ADL") == 0) {
    671429                struct xt_node *adl, *d, *c;
     
    716474                        }
    717475                }
    718         } else if (strcmp(cmd[0], "UBM") == 0) {
    719                 /* This one will give us msgs from federated networks. Technically
    720                    it should also get us offline messages, but I don't know how
    721                    I can signal MSN servers to use it. */
    722                 char *ct, *handle;
    723 
    724                 if (strcmp(cmd[1], ic->acc->user) == 0) {
    725                         /* With MPOP, you'll get copies of your own msgs from other
    726                            sessions. Discard those at least for now. */
    727                         return 1;
    728                 }
    729 
    730                 ct = get_rfc822_header(msg, "Content-Type", msglen);
    731                 if (strncmp(ct, "text/plain", 10) != 0) {
    732                         /* Typing notification or something? */
    733                         g_free(ct);
    734                         return 1;
    735                 }
    736                 if (strcmp(cmd[2], "1") != 0) {
    737                         handle = g_strdup_printf("%s:%s", cmd[2], cmd[1]);
    738                 } else {
    739                         handle = g_strdup(cmd[1]);
    740                 }
    741 
    742                 imcb_buddy_msg(ic, handle, body, 0, 0);
    743                 g_free(handle);
     476        } else if ((strcmp(cmd[0], "SDG") == 0) || (strcmp(cmd[0], "NFY") == 0)) {
     477                msn_ns_structured_message(md, msg, msglen, cmd);
    744478        }
    745479
    746480        return 1;
     481}
     482
     483static 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
     510cleanup:
     511        g_strfreev(parts);
     512        g_free(action);
     513        g_free(from);
     514        g_free(who);
     515}
     516
     517static 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
     528static 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
     584cleanup:
     585        xt_free_node(body);
    747586}
    748587
     
    768607void msn_auth_got_contact_list(struct im_connection *ic)
    769608{
    770         struct msn_data *md;
    771 
    772609        /* Dead connection? */
    773610        if (g_slist_find(msn_connections, ic) == NULL) {
     
    775612        }
    776613
    777         md = ic->proto_data;
    778         msn_ns_write(ic, -1, "BLP %d %s\r\n", ++md->trId, "BL");
     614        msn_ns_send_adl_start(ic);
     615        msn_ns_finish_login(ic);
    779616}
    780617
    781618static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data)
    782619{
    783         struct xt_node *adl = data, *d, *c;
     620        struct xt_node *adl = data, *d, *c, *s;
    784621        struct bee_user *bu = value;
    785622        struct msn_buddy_data *bd = bu->data;
     
    810647        c = xt_new_node("c", NULL, NULL);
    811648        xt_add_attr(c, "n", handle);
    812         xt_add_attr(c, "l", l);
    813649        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);
    814654        xt_insert_child(d, c);
    815655
     
    881721
    882722        if ((md->flags & MSN_DONE_ADL) && (md->flags & MSN_GOT_PROFILE)) {
    883                 if (md->flags & MSN_EMAIL_UNVERIFIED) {
    884                         imcb_connected(ic);
    885                 } else {
    886                         return msn_ns_set_display_name(ic, set_getstr(&ic->acc->set, "display_name"));
    887                 }
     723                imcb_connected(ic);
    888724        }
    889725
     
    891727}
    892728
     729// TODO: typing notifications, nudges lol, etc
    893730int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text)
    894731{
    895732        struct msn_data *md = ic->proto_data;
    896         int type = 0;
    897         char *buf, *handle;
     733        int retval = 0;
     734        char *buf;
    898735
    899736        if (strncmp(text, "\r\r\r", 3) == 0) {
     
    903740        }
    904741
    905         /* This might be a federated contact. Get its network number,
    906            prefixed to bu->handle with a colon. Default is 1. */
    907         for (handle = bu->handle; g_ascii_isdigit(*handle); handle++) {
    908                 type = type * 10 + *handle - '0';
    909         }
    910         if (*handle == ':') {
    911                 handle++;
    912         } else {
    913                 type = 1;
    914         }
    915 
    916         buf = g_strdup_printf("%s%s", MSN_MESSAGE_HEADERS, text);
    917 
    918         if (msn_ns_write(ic, -1, "UUM %d %s %d %d %zd\r\n%s",
    919                          ++md->trId, handle, type,
    920                          1,          /* type == IM (not nudge/typing) */
    921                          strlen(buf), buf)) {
    922                 return 1;
    923         } else {
    924                 return 0;
    925         }
    926 }
    927 
    928 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq)
    929 {
    930         GSList *l;
    931 
    932         for (l = *msgq; l; l = l->next) {
    933                 struct msn_message *m = l->data;
    934                 bee_user_t *bu = bee_user_by_handle(ic->bee, ic, m->who);
    935 
    936                 if (bu) {
    937                         if (!msn_ns_sendmessage(ic, bu, m->text)) {
    938                                 return;
    939                         }
    940                 }
    941         }
    942 
    943         while (*msgq != NULL) {
    944                 struct msn_message *m = (*msgq)->data;
    945 
    946                 g_free(m->who);
    947                 g_free(m->text);
    948                 g_free(m);
    949 
    950                 *msgq = g_slist_remove(*msgq, m);
    951         }
    952 }
     742        buf = g_strdup_printf(MSN_MESSAGE_HEADERS, bu->handle, ic->acc->user, md->uuid, strlen(text), text);
     743        retval = msn_ns_write(ic, -1, "SDG %d %zd\r\n%s", ++md->trId, strlen(buf), buf);
     744        g_free(buf);
     745        return retval;
     746}
  • protocols/msn/soap.c

    r531eabd rb1dc403  
    209209                return;
    210210        }
     211        fprintf(stderr, "\n\x1b[90mSOAP:\n");
    211212
    212213        if (headers) {
     
    225226                xt_free_node(xt);
    226227        }
     228        fprintf(stderr, "\n\x1b[97m\n");
    227229}
    228230
  • protocols/msn/soap.h

    r531eabd rb1dc403  
    167167
    168168#define SOAP_MEMLIST_PAYLOAD \
    169         "<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\"><serviceFilter xmlns=\"http://www.msn.com/webservices/AddressBook\"><Types xmlns=\"http://www.msn.com/webservices/AddressBook\"><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Messenger</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Invitation</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">SocialNetwork</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Space</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Profile</ServiceType></Types></serviceFilter>" \
     169        "<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\"><serviceFilter><Types><ServiceType>Messenger</ServiceType><ServiceType>IMAvailability</ServiceType></Types></serviceFilter><expandMembership>true</expandMembership>" \
    170170        "</FindMembership>"
    171171
  • protocols/msn/tables.c

    r531eabd rb1dc403  
    7373        { 206, "Domain name missing",                                   0 },
    7474        { 207, "Already logged in",                                     0 },
    75         { 208, "Invalid handle",                                        STATUS_SB_IM_SPARE },
     75        { 208, "Invalid handle",                                        0 },
    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",                                 STATUS_SB_IM_SPARE },
    80         { 217, "Person is off-line or non-existent",                    STATUS_SB_IM_SPARE },
     79        { 216, "Handle is not in list",                                 0 },
     80        { 217, "Person is off-line or non-existent",                    0 },
    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",                                   STATUS_SB_IM_SPARE },
     115        { 713, "Calling too rapidly",                                   0 },
    116116        { 714, "Too many sessions",                                     STATUS_FATAL },
    117117        { 715, "Not expected/Invalid argument/action",                  0 },
  • protocols/nogaim.c

    r531eabd rb1dc403  
    503503};
    504504
    505 static void imcb_ask_auth_cb_no(void *data)
     505static void imcb_ask_cb_free(void *data)
    506506{
    507507        struct imcb_ask_cb_data *cbd = data;
    508 
    509         cbd->ic->acc->prpl->auth_deny(cbd->ic, cbd->handle);
    510508
    511509        g_free(cbd->handle);
     
    513511}
    514512
     513static void imcb_ask_auth_cb_no(void *data)
     514{
     515        struct imcb_ask_cb_data *cbd = data;
     516
     517        cbd->ic->acc->prpl->auth_deny(cbd->ic, cbd->handle);
     518
     519        imcb_ask_cb_free(cbd);
     520}
     521
    515522static void imcb_ask_auth_cb_yes(void *data)
    516523{
     
    519526        cbd->ic->acc->prpl->auth_allow(cbd->ic, cbd->handle);
    520527
    521         g_free(cbd->handle);
    522         g_free(cbd);
     528        imcb_ask_cb_free(cbd);
    523529}
    524530
     
    540546        data->handle = g_strdup(handle);
    541547        query_add((irc_t *) ic->bee->ui_data, ic, s,
    542                   imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, g_free, data);
    543 }
    544 
    545 
    546 static void imcb_ask_add_cb_no(void *data)
    547 {
    548         g_free(((struct imcb_ask_cb_data*) data)->handle);
    549         g_free(data);
     548                  imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, imcb_ask_cb_free, data);
     549
     550        g_free(s);
    550551}
    551552
     
    556557        cbd->ic->acc->prpl->add_buddy(cbd->ic, cbd->handle, NULL);
    557558
    558         imcb_ask_add_cb_no(data);
     559        imcb_ask_cb_free(data);
    559560}
    560561
    561562void imcb_ask_add(struct im_connection *ic, const char *handle, const char *realname)
    562563{
    563         struct imcb_ask_cb_data *data = g_new0(struct imcb_ask_cb_data, 1);
     564        struct imcb_ask_cb_data *data;
    564565        char *s;
    565566
     
    569570        }
    570571
     572        data = g_new0(struct imcb_ask_cb_data, 1);
     573
    571574        s = g_strdup_printf("The user %s is not in your buddy list yet. Do you want to add him/her now?", handle);
    572575
     
    574577        data->handle = g_strdup(handle);
    575578        query_add((irc_t *) ic->bee->ui_data, ic, s,
    576                   imcb_ask_add_cb_yes, imcb_ask_add_cb_no, g_free, data);
     579                  imcb_ask_add_cb_yes, imcb_ask_cb_free, imcb_ask_cb_free, data);
     580
     581        g_free(s);
    577582}
    578583
  • protocols/purple/ft-direct.c

    r531eabd rb1dc403  
    2828
    2929#include "bitlbee.h"
     30#include "bpurple.h"
    3031
    3132#include <stdarg.h>
     
    207208void purple_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *handle)
    208209{
    209         PurpleAccount *pa = ic->proto_data;
     210        struct purple_data *pd = ic->proto_data;
    210211        struct prpl_xfer_data *px;
    211212
     
    213214           multi-threaded anyway. */
    214215        next_ft = ft;
    215         serv_send_file(purple_account_get_connection(pa), handle, ft->file_name);
     216        serv_send_file(purple_account_get_connection(pd->account), handle,
     217                       ft->file_name);
    216218
    217219        ft->write = prpl_xfer_write;
  • protocols/purple/ft.c

    r531eabd rb1dc403  
    2828
    2929#include "bitlbee.h"
     30#include "bpurple.h"
    3031
    3132#include <stdarg.h>
     
    285286{
    286287        struct prpl_xfer_data *px = ft->data;
    287         PurpleAccount *pa = px->ic->proto_data;
     288        struct purple_data *pd = px->ic->proto_data;
    288289
    289290        /* xfer_new() will pick up this variable. It's a hack but we're not
    290291           multi-threaded anyway. */
    291292        next_ft = ft;
    292         serv_send_file(purple_account_get_connection(pa), px->handle, px->fn);
     293        serv_send_file(purple_account_get_connection(pd->account),
     294                   px->handle, px->fn);
    293295}
    294296
  • protocols/purple/purple.c

    r531eabd rb1dc403  
    2323
    2424#include "bitlbee.h"
     25#include "bpurple.h"
    2526#include "help.h"
    2627
     
    3940static char *set_eval_display_name(set_t *set, char *value);
    4041
     42void purple_request_input_callback(guint id, struct im_connection *ic,
     43                                   const char *message, const char *who);
     44
     45/* purple_request_input specific stuff */
     46typedef void (*ri_callback_t)(gpointer, const gchar *);
     47
     48struct 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
    4156struct im_connection *purple_ic_by_pa(PurpleAccount *pa)
    4257{
    4358        GSList *i;
     59        struct purple_data *pd;
    4460
    4561        for (i = purple_connections; i; i = i->next) {
    46                 if (((struct im_connection *) i->data)->proto_data == pa) {
     62                pd = ((struct im_connection *) i->data)->proto_data;
     63                if (pd->account == pa) {
    4764                        return i->data;
    4865                }
     
    290307{
    291308        struct im_connection *ic = imcb_new(acc);
    292         PurpleAccount *pa;
     309        struct purple_data *pd;
    293310
    294311        if ((local_bee != NULL && local_bee != acc->bee) ||
     
    306323        purple_connections = g_slist_prepend(purple_connections, ic);
    307324
    308         ic->proto_data = pa = purple_account_new(acc->user, (char *) acc->prpl->data);
    309         purple_account_set_password(pa, acc->pass);
    310         purple_sync_settings(acc, pa);
    311 
    312         purple_account_set_enabled(pa, "BitlBee", TRUE);
     325        ic->proto_data = pd = g_new0(struct purple_data, 1);
     326        pd->account = purple_account_new(acc->user, (char *) acc->prpl->data);
     327        pd->input_requests = g_hash_table_new_full(g_direct_hash, g_direct_equal,
     328                                                   NULL, g_free);
     329        pd->next_request_id = 0;
     330        purple_account_set_password(pd->account, acc->pass);
     331        purple_sync_settings(acc, pd->account);
     332
     333        purple_account_set_enabled(pd->account, "BitlBee", TRUE);
    313334}
    314335
    315336static void purple_logout(struct im_connection *ic)
    316337{
    317         PurpleAccount *pa = ic->proto_data;
    318 
    319         purple_account_set_enabled(pa, "BitlBee", FALSE);
     338        struct purple_data *pd = ic->proto_data;
     339
     340        if (!pd) {
     341                return;
     342        }
     343
     344        purple_account_set_enabled(pd->account, "BitlBee", FALSE);
    320345        purple_connections = g_slist_remove(purple_connections, ic);
    321         purple_accounts_remove(pa);
     346        purple_accounts_remove(pd->account);
     347        g_hash_table_destroy(pd->input_requests);
     348        g_free(pd);
    322349}
    323350
     
    325352{
    326353        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        }
    327361
    328362        if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
    329                                                           who, ic->proto_data)) == NULL) {
     363                                                          who, pd->account)) == NULL) {
    330364                conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,
    331                                                ic->proto_data, who);
     365                                               pd->account, who);
    332366        }
    333367
     
    339373static GList *purple_away_states(struct im_connection *ic)
    340374{
    341         PurpleAccount *pa = ic->proto_data;
     375        struct purple_data *pd = ic->proto_data;
    342376        GList *st, *ret = NULL;
    343377
    344         for (st = purple_account_get_status_types(pa); st; st = st->next) {
     378        for (st = purple_account_get_status_types(pd->account); st; st = st->next) {
    345379                PurpleStatusPrimitive prim = purple_status_type_get_primitive(st->data);
    346380                if (prim != PURPLE_STATUS_AVAILABLE && prim != PURPLE_STATUS_OFFLINE) {
     
    354388static void purple_set_away(struct im_connection *ic, char *state_txt, char *message)
    355389{
    356         PurpleAccount *pa = ic->proto_data;
    357         GList *status_types = purple_account_get_status_types(pa), *st;
     390        struct purple_data *pd = ic->proto_data;
     391        GList *status_types = purple_account_get_status_types(pd->account), *st;
    358392        PurpleStatusType *pst = NULL;
    359393        GList *args = NULL;
     
    378412        }
    379413
    380         purple_account_set_status_list(pa, st ? purple_status_type_get_id(pst) : "away",
     414        purple_account_set_status_list(pd->account,
     415                                       st ? purple_status_type_get_id(pst) : "away",
    381416                                       TRUE, args);
    382417
     
    447482        PurpleBuddy *pb;
    448483        PurpleGroup *pg = NULL;
     484        struct purple_data *pd = ic->proto_data;
    449485
    450486        if (group && !(pg = purple_find_group(group))) {
     
    453489        }
    454490
    455         pb = purple_buddy_new((PurpleAccount *) ic->proto_data, who, NULL);
     491        pb = purple_buddy_new(pd->account, who, NULL);
    456492        purple_blist_add_buddy(pb, NULL, pg, NULL);
    457         purple_account_add_buddy((PurpleAccount *) ic->proto_data, pb);
    458 
    459         purple_gg_buddylist_export(((PurpleAccount *) ic->proto_data)->gc);
     493        purple_account_add_buddy(pd->account, pb);
     494
     495        purple_gg_buddylist_export(pd->account->gc);
    460496}
    461497
     
    463499{
    464500        PurpleBuddy *pb;
    465 
    466         pb = purple_find_buddy((PurpleAccount *) ic->proto_data, who);
     501        struct purple_data *pd = ic->proto_data;
     502
     503        pb = purple_find_buddy(pd->account, who);
    467504        if (pb != NULL) {
    468505                PurpleGroup *group;
    469506
    470507                group = purple_buddy_get_group(pb);
    471                 purple_account_remove_buddy((PurpleAccount *) ic->proto_data, pb, group);
     508                purple_account_remove_buddy(pd->account, pb, group);
    472509
    473510                purple_blist_remove_buddy(pb);
    474511        }
    475512
    476         purple_gg_buddylist_export(((PurpleAccount *) ic->proto_data)->gc);
     513        purple_gg_buddylist_export(pd->account->gc);
    477514}
    478515
    479516static void purple_add_permit(struct im_connection *ic, char *who)
    480517{
    481         PurpleAccount *pa = ic->proto_data;
    482 
    483         purple_privacy_permit_add(pa, who, FALSE);
     518        struct purple_data *pd = ic->proto_data;
     519
     520        purple_privacy_permit_add(pd->account, who, FALSE);
    484521}
    485522
    486523static void purple_add_deny(struct im_connection *ic, char *who)
    487524{
    488         PurpleAccount *pa = ic->proto_data;
    489 
    490         purple_privacy_deny_add(pa, who, FALSE);
     525        struct purple_data *pd = ic->proto_data;
     526
     527        purple_privacy_deny_add(pd->account, who, FALSE);
    491528}
    492529
    493530static void purple_rem_permit(struct im_connection *ic, char *who)
    494531{
    495         PurpleAccount *pa = ic->proto_data;
    496 
    497         purple_privacy_permit_remove(pa, who, FALSE);
     532        struct purple_data *pd = ic->proto_data;
     533
     534        purple_privacy_permit_remove(pd->account, who, FALSE);
    498535}
    499536
    500537static void purple_rem_deny(struct im_connection *ic, char *who)
    501538{
    502         PurpleAccount *pa = ic->proto_data;
    503 
    504         purple_privacy_deny_remove(pa, who, FALSE);
     539        struct purple_data *pd = ic->proto_data;
     540
     541        purple_privacy_deny_remove(pd->account, who, FALSE);
    505542}
    506543
    507544static void purple_get_info(struct im_connection *ic, char *who)
    508545{
    509         serv_get_info(purple_account_get_connection(ic->proto_data), who);
     546        struct purple_data *pd = ic->proto_data;
     547
     548        serv_get_info(purple_account_get_connection(pd->account), who);
    510549}
    511550
     
    517556{
    518557        PurpleTypingState state = PURPLE_NOT_TYPING;
    519         PurpleAccount *pa = ic->proto_data;
     558        struct purple_data *pd = ic->proto_data;
    520559
    521560        if (flags & OPT_TYPING) {
     
    525564        }
    526565
    527         serv_send_typing(purple_account_get_connection(pa), who, state);
     566        serv_send_typing(purple_account_get_connection(pd->account), who, state);
    528567
    529568        return 1;
     
    559598        /* There went my nice afternoon. :-( */
    560599
    561         PurpleAccount *pa = ic->proto_data;
    562         PurplePlugin *prpl = purple_plugins_find_with_id(pa->protocol_id);
     600        struct purple_data *pd = ic->proto_data;
     601        PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id);
    563602        PurplePluginProtocolInfo *pi = prpl->info->extra_info;
    564         PurpleBuddy *pb = purple_find_buddy((PurpleAccount *) ic->proto_data, who);
     603        PurpleBuddy *pb = purple_find_buddy(pd->account, who);
    565604        PurpleMenuAction *mi;
    566605        GList *menu;
     
    597636        PurpleConversation *pc = gc->data;
    598637        PurpleConvChat *pcc = PURPLE_CONV_CHAT(pc);
    599 
    600         serv_chat_invite(purple_account_get_connection(gc->ic->proto_data),
     638        struct purple_data *pd = gc->ic->proto_data;
     639
     640        serv_chat_invite(purple_account_get_connection(pd->account),
    601641                         purple_conv_chat_get_id(pcc),
    602642                         message && *message ? message : "Please join my chat",
     
    623663                                   set_t **sets)
    624664{
    625         PurpleAccount *pa = ic->proto_data;
    626         PurplePlugin *prpl = purple_plugins_find_with_id(pa->protocol_id);
     665        struct purple_data *pd = ic->proto_data;
     666        PurplePlugin *prpl = purple_plugins_find_with_id(pd->account->protocol_id);
    627667        PurplePluginProtocolInfo *pi = prpl->info->extra_info;
    628668        GHashTable *chat_hash;
     
    631671
    632672        if (!pi->chat_info || !pi->chat_info_defaults ||
    633             !(info = pi->chat_info(purple_account_get_connection(pa)))) {
     673            !(info = pi->chat_info(purple_account_get_connection(pd->account)))) {
    634674                imcb_error(ic, "Joining chatrooms not supported by this protocol");
    635675                return NULL;
    636676        }
    637677
    638         if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, room, pa))) {
     678        if ((conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
     679                                                          room, pd->account))) {
    639680                purple_conversation_destroy(conv);
    640681        }
    641682
    642         chat_hash = pi->chat_info_defaults(purple_account_get_connection(pa), room);
     683        chat_hash = pi->chat_info_defaults(
     684                purple_account_get_connection(pd->account), room
     685        );
    643686
    644687        for (l = info; l; l = l->next) {
     
    654697        }
    655698
    656         serv_join_chat(purple_account_get_connection(pa), chat_hash);
     699        serv_join_chat(purple_account_get_connection(pd->account), chat_hash);
    657700
    658701        return NULL;
     
    9811024                pqad->yes(pqad->user_data, pqad->yes_i);
    9821025        }
    983         g_free(pqad);
    9841026}
    9851027
     
    9911033                pqad->no(pqad->user_data, pqad->no_i);
    9921034        }
    993         g_free(pqad);
     1035}
     1036
     1037/* q->free() callback from query_del()*/
     1038static 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);
    9941044}
    9951045
     
    10261076        q = g_strdup_printf("Request: %s\n\n%s\n\n%s", title, primary, secondary);
    10271077        pqad->bee_data = query_add(local_bee->ui_data, purple_ic_by_pa(account), q,
    1028                                    prplcb_request_action_yes, prplcb_request_action_no, g_free, pqad);
     1078                                   prplcb_request_action_yes, prplcb_request_action_no,
     1079                                   prplcb_request_action_free, pqad);
    10291080
    10301081        g_free(q);
     
    10331084}
    10341085
    1035 /*
    1036 static void prplcb_request_test()
    1037 {
    1038         fprintf( stderr, "bla\n" );
    1039 }
    1040 */
     1086/* So it turns out some requests have no account context at all, because
     1087 * libpurple hates us. This means that query_del_by_conn() won't remove those
     1088 * on logout, and will segfault if the user replies. That's why this exists.
     1089 */
     1090static 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
     1123void* 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
     1147void 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
    10411162
    10421163static PurpleRequestUiOps bee_request_uiops =
    10431164{
    1044         NULL,
     1165        prplcb_request_input,
    10451166        NULL,
    10461167        prplcb_request_action,
    10471168        NULL,
    10481169        NULL,
    1049         NULL,
     1170        prplcb_close_request,
    10501171        NULL,
    10511172};
  • protocols/skype/Makefile

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

    r531eabd rb1dc403  
    852852}
    853853
     854/* Parses a decimal or hex tweet ID, returns TRUE on success */
     855static 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
     869bee_user_t twitter_log_local_user;
     870
    854871/** Convert the given bitlbee tweet ID, bitlbee username, or twitter tweet ID
    855872 *  into a twitter tweet ID.
     
    879896                        arg++;
    880897                }
    881                 if (sscanf(arg, "%" G_GINT64_MODIFIER "x", &id) == 1 &&
    882                     id < TWITTER_LOG_LENGTH) {
     898                if (twitter_parse_id(arg, 16, &id) && id < TWITTER_LOG_LENGTH) {
    883899                        bu = td->log[id].bu;
    884900                        id = td->log[id].id;
    885                         /* Beware of dangling pointers! */
    886                         if (!g_slist_find(ic->bee->users, bu)) {
    887                                 bu = NULL;
    888                         }
    889                 } else if (sscanf(arg, "%" G_GINT64_MODIFIER "d", &id) == 1) {
     901                } else if (twitter_parse_id(arg, 10, &id)) {
    890902                        /* Allow normal tweet IDs as well; not a very useful
    891903                           feature but it's always been there. Just ignore
     
    897909        }
    898910        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                }
    899921                *bu_ = bu;
    900922        }
     
    9891011                in_reply_to = id;
    9901012                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
    9911026        } else if (g_strcasecmp(cmd[0], "post") == 0) {
    9921027                message += 5;
  • protocols/twitter/twitter.h

    r531eabd rb1dc403  
    101101struct twitter_log_data {
    102102        guint64 id;
    103         struct bee_user *bu; /* DANGER: can be a dead pointer. Check it first. */
     103        /* DANGER: bu can be a dead pointer. Check it first.
     104         * twitter_message_id_from_command_arg() will do this. */
     105        struct bee_user *bu;
    104106};
    105107
     
    110112 */
    111113extern 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 */
     121extern bee_user_t twitter_log_local_user;
    112122
    113123void twitter_login_finish(struct im_connection *ic);
  • protocols/twitter/twitter_lib.c

    r531eabd rb1dc403  
    460460#endif
    461461
    462 static char* expand_entities(char* text, const json_value *entities);
     462static void expand_entities(char **text, const json_value *node);
    463463
    464464/**
     
    473473{
    474474        struct twitter_xml_status *txs;
    475         const json_value *rt = NULL, *entities = NULL;
     475        const json_value *rt = 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;
    505503                }
    506504        }
     
    516514                        txs_free(rtxs);
    517515                }
    518         } else if (entities) {
    519                 txs->text = expand_entities(txs->text, entities);
     516        } else {
     517                expand_entities(&txs->text, node);
    520518        }
    521519
     
    534532{
    535533        struct twitter_xml_status *txs;
    536         const json_value *entities = NULL;
    537534
    538535        if (node->type != json_object) {
     
    561558        }
    562559
    563         if (entities) {
    564                 txs->text = expand_entities(txs->text, entities);
    565         }
     560        expand_entities(&txs->text, node);
    566561
    567562        if (txs->text && txs->user && txs->id) {
     
    573568}
    574569
    575 static char* expand_entities(char* text, const json_value *entities)
    576 {
     570static 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
    577590        JSON_O_FOREACH(entities, k, v) {
    578591                int i;
     
    586599
    587600                for (i = 0; i < v->u.array.length; i++) {
     601                        const char *format = "%s%s <%s>%s";
     602
    588603                        if (v->u.array.values[i]->type != json_object) {
    589604                                continue;
     
    592607                        const char *kort = json_o_str(v->u.array.values[i], "url");
    593608                        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");
    594610                        char *pos, *new;
    595611
    596                         if (!kort || !disp || !(pos = strstr(text, kort))) {
     612                        if (!kort || !disp || !(pos = strstr(*text, kort))) {
    597613                                continue;
    598614                        }
     615                        if (quote_url && strstr(full, quote_url)) {
     616                                format = "%s<%s> [%s]%s";
     617                                disp = quote_text;
     618                        }
    599619
    600620                        *pos = '\0';
    601                         new = g_strdup_printf("%s%s <%s>%s", text, kort,
     621                        new = g_strdup_printf(format, *text, kort,
    602622                                              disp, pos + strlen(kort));
    603623
    604                         g_free(text);
    605                         text = new;
    606                 }
    607         }
    608 
    609         return text;
     624                        g_free(*text);
     625                        *text = new;
     626                }
     627        }
     628        g_free(quote_text);
     629        g_free(quote_url);
    610630}
    611631
     
    681701        if (g_strcasecmp(txs->user->screen_name, td->user) == 0) {
    682702                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;
    683705        }
    684706
     
    832854
    833855        last_id_str = g_strdup_printf("%" G_GUINT64_FORMAT, td->timeline_id);
    834         set_setstr(&ic->acc->set, "last_tweet", last_id_str);
     856        set_setstr(&ic->acc->set, "_last_tweet", last_id_str);
    835857        g_free(last_id_str);
    836858}
     
    862884
    863885                imcb_error(ic, "Stream closed (%s)", req->status_string);
     886                if (req->status_code == 401) {
     887                        imcb_error(ic, "Check your system clock.");
     888                }
    864889                imc_logout(ic, TRUE);
    865890                return;
  • protocols/yahoo/yahoo.c

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

    r531eabd rb1dc403  
    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                }
    105109                local = protocol_account_islocal(protocol);
    106110        }
     
    124128                }
    125129        } else {
     130                g_free(pass_cr);
     131                g_free(password);
    126132                return XT_ABORT;
    127133        }
     
    197203        fn = g_strconcat(global.conf->configdir, xd->given_nick, ".xml", NULL);
    198204        if ((fd = open(fn, O_RDONLY)) < 0) {
    199                 ret = STORAGE_NO_SUCH_USER;
     205                if (errno == ENOENT) {
     206                        ret = STORAGE_NO_SUCH_USER;
     207                } else {
     208                        irc_rootmsg(irc, "Error loading user config: %s", g_strerror(errno));
     209                }
    200210                goto error;
    201211        }
     
    259269
    260270
    261 static gboolean xml_generate_nick(gpointer key, gpointer value, gpointer data);
    262271static void xml_generate_settings(struct xt_node *cur, set_t **head);
    263272
     
    292301
    293302        for (acc = irc->b->accounts; acc; acc = acc->next) {
     303                GHashTableIter iter;
     304                gpointer key, value;
    294305                unsigned char *pass_cr;
    295306                char *pass_b64;
     
    312323                g_free(pass_b64);
    313324
    314                 /* This probably looks pretty strange. g_hash_table_foreach
    315                    is quite a PITA already (but it can't get much better in
    316                    C without using #define, I'm afraid), and it
    317                    doesn't seem to be possible to abort the foreach on write
    318                    errors, so instead let's use the _find function and
    319                    return TRUE on write errors. Which means, if we found
    320                    something, there was an error. :-) */
    321                 g_hash_table_find(acc->nicks, xml_generate_nick, cur);
     325                g_hash_table_iter_init(&iter, acc->nicks);
     326                while (g_hash_table_iter_next(&iter, &key, &value)) {
     327                        struct xt_node *node = xt_new_node("buddy", NULL, NULL);
     328                        xt_add_attr(node, "handle", key);
     329                        xt_add_attr(node, "nick", value);
     330                        xt_add_child(cur, node);
     331                }
    322332
    323333                xml_generate_settings(cur, &acc->set);
     
    343353
    344354        return root;
    345 }
    346 
    347 static gboolean xml_generate_nick(gpointer key, gpointer value, gpointer data)
    348 {
    349         struct xt_node *node = xt_new_node("buddy", NULL, NULL);
    350 
    351         xt_add_attr(node, "handle", key);
    352         xt_add_attr(node, "nick", value);
    353         xt_add_child((struct xt_node *) data, node);
    354 
    355         return FALSE;
    356355}
    357356
     
    388387        strcat(path, ".XXXXXX");
    389388        if ((fd = mkstemp(path)) < 0) {
    390                 irc_rootmsg(irc, "Error while opening configuration file.");
    391                 return STORAGE_OTHER_ERROR;
     389                goto error;
    392390        }
    393391
     
    411409
    412410error:
    413         irc_rootmsg(irc, "Write error. Disk full?");
     411        irc_rootmsg(irc, "Write error: %s", g_strerror(errno));
    414412        ret = STORAGE_OTHER_ERROR;
    415413
Note: See TracChangeset for help on using the changeset viewer.