# HG changeset patch # User Christian Hammond # Date 1062477136 0 # Node ID b7e113a59b51ecd078c813e806aa807eacd79ffb # Parent 57161e3abbb52828c8bf35f6339014c2e15f178e [gaim-migrate @ 7227] Updated to MSN Protocol 9. committer: Tailor Script diff -r 57161e3abbb5 -r b7e113a59b51 ChangeLog --- a/ChangeLog Tue Sep 02 04:28:34 2003 +0000 +++ b/ChangeLog Tue Sep 02 04:32:16 2003 +0000 @@ -2,6 +2,7 @@ version 0.69 * Contact (aka Person, aka Meta-Contact, aka Buddy Merging, etc) Support + * Updated MSN support to the MSN Protocol version 9. * Yahoo now shows people using the java chat client (Tim Ringenbach) version 0.68 (09/01/2003): diff -r 57161e3abbb5 -r b7e113a59b51 Makefile.am --- a/Makefile.am Tue Sep 02 04:28:34 2003 +0000 +++ b/Makefile.am Tue Sep 02 04:32:16 2003 +0000 @@ -24,6 +24,9 @@ dist-hook: gaim.spec cp gaim.spec $(distdir) +distcheck-hook: plugins/perl/common/Gaim.pm +# cp plugins/perl/common/Gaim.pm $(distdir)/plugins/perl/common + appsdir = $(datadir)/applications apps_DATA = gaim.desktop diff -r 57161e3abbb5 -r b7e113a59b51 configure.ac --- a/configure.ac Tue Sep 02 04:28:34 2003 +0000 +++ b/configure.ac Tue Sep 02 04:32:16 2003 +0000 @@ -334,6 +334,244 @@ AM_CONDITIONAL(USE_PERL, false) fi +dnl ####################################################################### +dnl # SSL support +dnl # +dnl # Thanks go to Evolution for the checks. +dnl ####################################################################### +AC_ARG_ENABLE(ssl, + [ --enable-ssl=[yes,no,static] Turn on Secure Sockets Layer support [default=yes]], + [enable_nss="$enableval"], + [enable_nss="yes"]) + +AC_ARG_WITH(nspr-includes, + [ --with-nspr-includes=PREFIX Specify location of Mozilla nspr4 includes.], + [with_nspr_includes="$withval"]) + +AC_ARG_WITH(nspr-libs, + [ --with-nspr-libs=PREFIX Specify location of Mozilla nsp4 libs.], + [with_nspr_libs="$withval"]) + +AC_ARG_WITH(nss-includes, + [ --with-nss-includes=PREFIX Specify location of Mozilla nss3 includes.], + [with_nss_includes="$withval"]) + +AC_ARG_WITH(nss-libs, + [ --with-nss-libs=PREFIX Specify location of Mozilla nss3 libs.], + [with_nss_libs="$withval"]) + +msg_ssl="no" + +if test "x$enable_nss" = "xyes" || test "x$enable_nss" = "xstatic"; then + if test -n "$with_nspr_includes" || test -n "$with_nspr_libs" || \ + test -n "$with_nss_includes" || test -n "$with_nss_libs" || + test "x$enable_nss" = "xstatic"; then + + nss_manual_check="yes" + else + nss_manual_check="no" + fi + + if test "x$nss_manual_check" = "xno"; then + PKG_CHECK_MODULES(NSS, mozilla-nss, have_nss="yes") + + if test "x$have_nss" = "xyes"; then + mozilla_nspr="mozilla-nspr" + mozilla_nss="mozilla-nss" + + AC_DEFINE(HAVE_NSS, 1, [Define if you have Mozilla NSS]) + + msg_ssl="yes" + else + nss_manual_check="yes" + fi + fi + + if test "x$nss_manual_check" = "xyes"; then + mozilla_nss="" + have_nspr_includes="no" + + if test "x$with_nspr_includes" != "xno"; then + CPPFLAGS_save=$CPPFLAGS + + AC_MSG_CHECKING(for Mozilla nspr4 includes in $with_nspr_includes) + AC_MSG_RESULT("") + + CPPFLAGS="$CPPFLAGS -I$with_nspr_includes" + AC_CHECK_HEADERS(nspr.h prio.h, [ moz_nspr_includes="yes" ]) + CPPFLAGS=$CPPFLAGS_save + + if test "x$moz_nspr_includes" != "xno" -a \ + "x$moz_nspr_includes" != "x"; then + + have_nspr_includes="yes" + NSPR_CFLAGS="-I$with_nspr_includes" + fi + else + AC_MSG_CHECKING(for Mozilla nspr4 includes) + AC_MSG_RESULT(no) + fi + + have_nspr_libs="no" + + if test "x$with_nspr_libs" != "xno" -a \ + "x$have_nspr_includes" != "xno"; then + + CFLAGS_save=$CFLAGS + LDFLAGS_save=$LDFLAGS + + if test "$enable_nss" = "static"; then + if test -z "$with_nspr_libs"; then + AC_MSG_ERROR( + [Static linkage requested, but path to nspr libraries not set.] + [Please specify the path to libnspr4.a] + [Example: --with-nspr-libs=/usr/lib]) + else + nsprlibs="-ldl $with_nspr_libs/libplc4.a $with_nspr_libs/libplds4.a $with_nspr_libs/libnspr4.a $PTHREAD_LIB" + fi + else + nsprlibs="-ldl -lplc4 -lplds4 -lnspr4 $PTHREAD_LIB" + fi + + AC_CACHE_CHECK([for Mozilla nspr libraries], moz_nspr_libs, + [ + LIBS_save=$LIBS + CFLAGS="$CFLAGS $NSPR_CFLAGS" + + LIBS="$nsprlibs" + + if test "x$with_nspr_libs" != "x"; then + LDFLAGS="$LDFLAGS -L$with_nspr_libs" + else + LDFLAGS="$LDFLAGS" + fi + + AC_TRY_LINK_FUNC(PR_Init, + [moz_nspr_libs="yes"], + [moz_nspr_libs="no"]) + + CFLAGS=$CFLAGS_save + LDFLAGS=$LDFLAGS_save + LIBS=$LIBS_save + ]) + + if test "x$moz_nspr_libs" != "xno"; then + have_nspr_libs="yes" + NSPR_LIBS="-L$with_nspr_libs $nsprlibs" + else + NSPR_CFLAGS="" + fi + else + AC_MSG_CHECKING(for Mozilla nspr4 libraries) + AC_MSG_RESULT(no) + fi + + if test "x$with_nss_includes" != "xno" -a \ + "x$have_nspr_libs" != "xno"; then + + CPPFLAGS_save=$CPPFLAGS + + AC_MSG_CHECKING(for Mozilla nss3 includes in $with_nss_includes) + AC_MSG_RESULT("") + + if test "x$with_nspr_includes" != "x"; then + CPPFLAGS="$CPPFLAGS -I$with_nspr_includs -I$with_nss_includes" + else + CPPFLAGS="$CPPFLAGS -I$with_nss_includes" + fi + + AC_CHECK_HEADERS(nss.h ssl.h smime.h, + [have_nss_includes="yes"], + [have_nss_includes="no"]) + + CPPFLAGS=$CPPFLAGS_save + + if test "x$have_nss_includes" = "xyes"; then + have_nss_includes="yes" + NSS_CFLAGS="-I$with_nss_includes" + else + NSPR_CFLAGS="" + NSPR_LIBS="" + fi + else + AC_MSG_CHECKING(for Mozilla nss3 includes) + AC_MSG_RESULT(no) + fi + + if test "x$with_nss_libs" != "xno" -a \ + "x$have_nss_includes" != "xno"; then + + LDFLAGS_save=$LDFLAGS + + if test "$enable_nss" = "static"; then + if test -z "$with_nss_libs"; then + AC_MSG_ERROR( + [Static linkage requested, but path to nss libraries not set.] + [Please specify the path to libnss3.a] + [Example: --with-nspr-libs=/usr/lib/mozilla]) + else + nsslibs="-ldb1 $with_nss_libs/libnssckfw.a $with_nss_libs/libasn1.a $with_nss_libs/libcrmf.a $with_nss_libs/libswfci.a $with_nss_libs/libjar.a $with_nss_libs/libpkcs12.a $with_nss_libs/libpkcs7.a $with_nss_libs/libpki1.a $with_nss_libs/libsmime.a $with_nss_libs/libssl.a $with_nss_libs/libnss.a $with_nss_libs/libpk11wrap.a $with_nss_libs/libsoftokn.a $with_nss_libs/libfreebl.a $with_nss_libs/libnsspki.a $with_nss_libs/libnssdev.a $with_nss_libs/libcryptohi.a $with_nss_libs/libcerthi.a $with_nss_libs/libcertdb.a $with_nss_libs/libsecutil.a $with_nss_libs/libnssb.a" + + case "$host" in + *solaris*) + nsslibs="$nsslibs $with_nss_libs/libfreeb1.a" + ;; + esac + fi + else + nsslibs="-lssl3 -lsmime3 -lnss3 -lsoftokn3" + fi + + AC_CACHE_CHECK([for Mozilla nss libraries], moz_nss_libs, + [ + LIBS_save=$LIBS + LDFLAGS="$LDFLAGS -L$with_nspr_libs $nsprlibs -L$with_nss_libs $nsslibs" + LIBS="$nsslibs $nsprlibs" + + AC_TRY_LINK_FUNC(NSS_Init, + [moz_nss_libs="yes"], + [moz_nss_libs="no"]) + + if test "x$moz_nss_libs" = "xno"; then + nsslibs="-lssl3 -lsmime3 -lnss3 -lsoftokn3" + LDFLAGS="$LDFLAGS -L$with_nspr_libs $nsprlibs -L$with_nss_libs $nsslibs" + AC_TRY_LINK_FUNC(NSS_Init, + [moz_nss_libs="yes"], + [moz_nss_libs="no"]) + fi + + LDFLAGS=$LDFLAGS_save + LIBS=$LIBS_save + ]) + + if test "x$moz_nss_libs" != "xno"; then + AC_DEFINE(HAVE_NSS) + + NSS_LIBS="-L$with_nss_libs $nsslibs" + + if test "$enable_nss" = "static"; then + msg_ssl="yes (static)" + else + msg_ssl="yes" + fi + else + NSS_CFLAGS="" + NSPR_CFLAGS="" + NSPR_LIBS="" + fi + else + AC_MSG_CHECKING(for Mozilla nss libraries) + AC_MSG_ERROR(no) + fi + + NSS_CFLAGS="$NSPR_CFLAGS $NSS_CFLAGS" + NSS_LIBS="$NSPR_LIBS $NSS_LIBS" + fi + + AC_SUBST(NSS_CFLAGS) + AC_SUBST(NSS_LIBS) +fi + dnl Check for Tcl if test "$enable_tcl" = yes; then AC_MSG_CHECKING([for tclConfig.sh]) @@ -439,7 +677,7 @@ LDADD="$LDADD -static" DEBUG_CFLAGS="$DEBUG_CFLAGS -Wall -g" AC_DEFINE(DEBUG, 1, [Define if debugging is enabled.]) -fi +fi AC_SUBST(DEBUG_CFLAGS) AC_SUBST(LDADD) @@ -571,6 +809,7 @@ echo Build with Audio support...... : $enable_audio echo Build with NAS support........ : $enable_nas echo Build with GtkSpell support... : $enable_gtkspell +echo Build with Mozilla NSS support : $msg_ssl echo echo Use XScreenSaver Extension.... : $enable_xss echo Use X Session Management...... : $enable_sm diff -r 57161e3abbb5 -r b7e113a59b51 src/Makefile.am --- a/src/Makefile.am Tue Sep 02 04:28:34 2003 +0000 +++ b/src/Makefile.am Tue Sep 02 04:32:16 2003 +0000 @@ -89,6 +89,8 @@ status.h \ sound.c \ sound.h \ + sslconn.c \ + sslconn.h \ util.c \ util.h \ value.c \ @@ -162,7 +164,8 @@ $(XSS_LIBS) \ $(SM_LIBS) \ $(INTLLIBS) \ - $(GTKSPELL_LIBS) + $(GTKSPELL_LIBS) \ + $(NSS_LIBS) gaim_remote_SOURCES = \ gaim-remote.c @@ -181,4 +184,5 @@ $(AO_CFLAGS) \ $(DEBUG_CFLAGS) \ $(GTK_CFLAGS) \ - $(GTKSPELL_CFLAGS) + $(GTKSPELL_CFLAGS) \ + $(NSS_CFLAGS) diff -r 57161e3abbb5 -r b7e113a59b51 src/core.c --- a/src/core.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/core.c Tue Sep 02 04:32:16 2003 +0000 @@ -32,6 +32,7 @@ #include "privacy.h" #include "proxy.h" #include "signals.h" +#include "sslconn.h" #include "sound.h" struct GaimCore @@ -87,6 +88,7 @@ gaim_pounces_init(); gaim_proxy_init(); gaim_sound_init(); + gaim_ssl_init(); gaim_xfers_init(); if (ops != NULL && ops->ui_init != NULL) @@ -121,6 +123,7 @@ gaim_debug(GAIM_DEBUG_INFO, "main", "Unloading all plugins\n"); gaim_plugins_destroy_all(); + gaim_ssl_uninit(); gaim_blist_uninit(); gaim_conversations_uninit(); gaim_connections_uninit(); diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/Makefile.am --- a/src/protocols/msn/Makefile.am Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/Makefile.am Tue Sep 02 04:32:16 2003 +0000 @@ -19,6 +19,10 @@ msg.h \ msn.c \ msn.h \ + msnobject.c \ + msnobject.h \ + msnslp.c \ + msnslp.h \ notification.c \ notification.h \ page.c \ diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/buddyicon.c --- a/src/protocols/msn/buddyicon.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/buddyicon.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/buddyicon.h --- a/src/protocols/msn/buddyicon.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/buddyicon.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -24,7 +24,9 @@ typedef struct _MsnBuddyIconXfer MsnBuddyIconXfer; +#include "msg.h" #include "servconn.h" +#include "user.h" /** * State of a buddy icon transfer. diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/dispatch.c --- a/src/protocols/msn/dispatch.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/dispatch.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -27,28 +27,19 @@ static GHashTable *dispatch_commands = NULL; static gboolean -ver_cmd(MsnServConn *servconn, const char *command, const char **params, +cvr_cmd(MsnServConn *servconn, const char *command, const char **params, size_t param_count) { - GaimConnection *gc = servconn->session->account->gc; - size_t i; - gboolean msnp5_found = FALSE; + GaimAccount *account = servconn->session->account; + GaimConnection *gc = gaim_account_get_connection(account); + char outparams[MSN_BUF_LEN]; - for (i = 1; i < param_count; i++) { - if (!strcmp(params[i], "MSNP5")) { - msnp5_found = TRUE; - break; - } - } + g_snprintf(outparams, sizeof(outparams), + "TWN I %s", gaim_account_get_username(account)); - if (!msnp5_found) { - gaim_connection_error(gc, _("Protocol not supported")); - - return FALSE; - } - - if (!msn_servconn_send_command(servconn, "INF", NULL)) { - gaim_connection_error(gc, _("Unable to request INF")); + if (!msn_servconn_send_command(servconn, "USR", outparams)) + { + gaim_connection_error(gc, _("Unable to request USR\n")); return FALSE; } @@ -86,6 +77,62 @@ } static gboolean +ver_cmd(MsnServConn *servconn, const char *command, const char **params, + size_t param_count) +{ + MsnSession *session = servconn->session; + GaimAccount *account = session->account; + GaimConnection *gc = gaim_account_get_connection(account); + gboolean protocol_supported = FALSE; + char outparams[MSN_BUF_LEN]; + char proto_str[8]; + size_t i; + + g_snprintf(proto_str, sizeof(proto_str), "MSNP%d", session->protocol_ver); + + for (i = 1; i < param_count; i++) + { + if (!strcmp(params[i], proto_str)) + { + protocol_supported = TRUE; + break; + } + } + + if (!protocol_supported) + { + gaim_connection_error(gc, _("Protocol version not supported")); + + return FALSE; + } + + if (session->protocol_ver >= 8) + { + g_snprintf(outparams, sizeof(outparams), + "0x0409 winnt 5.1 i386 MSNMSGR 6.0.0602 MSMSGS %s", + gaim_account_get_username(account)); + + if (!msn_servconn_send_command(servconn, "CVR", outparams)) + { + gaim_connection_error(gc, _("Unable to request CVR\n")); + + return FALSE; + } + } + else + { + if (!msn_servconn_send_command(servconn, "INF", NULL)) + { + gaim_connection_error(gc, _("Unable to request INF\n")); + + return FALSE; + } + } + + return TRUE; +} + +static gboolean xfr_cmd(MsnServConn *servconn, const char *command, const char **params, size_t param_count) { @@ -95,7 +142,8 @@ int port; char *c; - if (param_count < 2 || strcmp(params[1], "NS")) { + if (param_count < 2 || strcmp(params[1], "NS")) + { gaim_connection_error(gc, _("Got invalid XFR")); return FALSE; @@ -103,7 +151,8 @@ host = g_strdup(params[2]); - if ((c = strchr(host, ':')) != NULL) { + if ((c = strchr(host, ':')) != NULL) + { *c = '\0'; port = atoi(c + 1); @@ -117,14 +166,16 @@ msn_servconn_destroy(servconn); session->dispatch_conn = NULL; + /* Reset our transaction ID. */ + session->trId = 0; + /* Now connect to the switchboard. */ session->notification_conn = msn_notification_new(session, host, port); g_free(host); - if (!msn_servconn_connect(session->notification_conn)) { + if (!msn_servconn_connect(session->notification_conn)) gaim_connection_error(gc, _("Unable to transfer")); - } return FALSE; } @@ -135,7 +186,8 @@ { GaimConnection *gc = servconn->session->account->gc; - if (isdigit(*command)) { + if (isdigit(*command)) + { char buf[4]; strncpy(buf, command, 4); @@ -155,8 +207,11 @@ MsnServConn *dispatch = data; MsnSession *session = dispatch->session; GaimConnection *gc = session->account->gc; + char proto_vers[256]; + size_t i; - if (source == -1) { + if (source == -1) + { gaim_connection_error(session->account->gc, _("Unable to connect")); return FALSE; } @@ -166,8 +221,21 @@ if (dispatch->fd != source) dispatch->fd = source; - if (!msn_servconn_send_command(dispatch, "VER", - "MSNP7 MSNP6 MSNP5 MSNP4 CVR0")) { + proto_vers[0] = '\0'; + + for (i = session->protocol_ver; i >= 7; i--) + { + char old_buf[256]; + + strcpy(old_buf, proto_vers); + + g_snprintf(proto_vers, sizeof(proto_vers), "MSNP%d %s", i, old_buf); + } + + strncat(proto_vers, "CVR0", sizeof(proto_vers)); + + if (!msn_servconn_send_command(dispatch, "VER", proto_vers)) + { gaim_connection_error(gc, _("Unable to write to server")); return FALSE; } @@ -195,15 +263,17 @@ MsnServConn *dispatch; dispatch = msn_servconn_new(session); - + msn_servconn_set_server(dispatch, server, port); msn_servconn_set_connect_cb(dispatch, connect_cb); msn_servconn_set_failed_read_cb(dispatch, failed_read_cb); if (dispatch_commands == NULL) { /* Register the command callbacks. */ + + msn_servconn_register_command(dispatch, "CVR", cvr_cmd); + msn_servconn_register_command(dispatch, "INF", inf_cmd); msn_servconn_register_command(dispatch, "VER", ver_cmd); - msn_servconn_register_command(dispatch, "INF", inf_cmd); msn_servconn_register_command(dispatch, "XFR", xfr_cmd); msn_servconn_register_command(dispatch, "_unknown_", unknown_cmd); diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/dispatch.h --- a/src/protocols/msn/dispatch.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/dispatch.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/error.c --- a/src/protocols/msn/error.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/error.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/error.h --- a/src/protocols/msn/error.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/error.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/ft.c --- a/src/protocols/msn/ft.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/ft.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003, Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/group.c --- a/src/protocols/msn/group.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/group.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/group.h --- a/src/protocols/msn/group.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/group.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -25,6 +25,8 @@ typedef struct _MsnGroup MsnGroup; typedef struct _MsnGroups MsnGroups; +#include + #include "session.h" #include "user.h" @@ -196,7 +198,7 @@ * Returns the number of groups in a groups list. * * @param groups The groups list. - * + * * @return The number of groups. */ size_t msn_groups_get_count(const MsnGroups *groups); diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/md5.h --- a/src/protocols/msn/md5.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/md5.h Tue Sep 02 04:32:16 2003 +0000 @@ -61,7 +61,7 @@ } md5_state_t; #ifdef __cplusplus -extern "C" +extern "C" { #endif diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/msg.c --- a/src/protocols/msn/msg.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/msg.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -72,7 +72,7 @@ msn_message_new_from_str(MsnSession *session, const char *str) { MsnMessage *msg; - char *tmp_base, *tmp, *field1, *field2, *c; + char *tmp_base, *msg_base, *tmp, *field1, *field2, *c; g_return_val_if_fail(str != NULL, NULL); g_return_val_if_fail(!g_ascii_strncasecmp(str, "MSG", 3), NULL); @@ -127,6 +127,8 @@ msg->flag = *field2; } + msg_base = tmp; + /* Back to the parsination. */ while (*tmp != '\r') { char *key, *value; @@ -164,7 +166,49 @@ tmp += 2; /* Now we *should* be at the body. */ - msn_message_set_body(msg, tmp); + if (!strcmp(msn_message_get_content_type(msg), "application/x-msnmsgrp2p")) + { + msn_message_set_body(msg, tmp); + } + else + { + char header[48]; + char footer[4]; + + msg->msnslp_message = TRUE; + + memcpy(header, tmp, 48); + + tmp += 48; + + msg->body = g_memdup(tmp, msg->size - (tmp - msg_base) + 1); + + tmp++; + + memcpy(footer, tmp, 4); + + /* Import the header. */ + memcpy(&msg->msnslp_header.session_id, tmp, 4); tmp += 4; + memcpy(&msg->msnslp_header.id, tmp, 4); tmp += 4; + memcpy(&msg->msnslp_header.offset, tmp, 4); tmp += 8; + memcpy(&msg->msnslp_header.total_size, tmp, 4); tmp += 8; + memcpy(&msg->msnslp_header.length, tmp, 4); tmp += 4; + memcpy(&msg->msnslp_header.flags, tmp, 4); tmp += 4; + memcpy(&msg->msnslp_header.prev_id, tmp, 4); tmp += 4; + memcpy(&msg->msnslp_header.prev_f9, tmp, 4); tmp += 4; + memcpy(&msg->msnslp_header.prev_total_size, tmp, 4); tmp += 8; + + /* Convert to the right endianness */ + msg->msnslp_header.session_id = ntohs(msg->msnslp_header.session_id); + msg->msnslp_header.id = ntohs(msg->msnslp_header.id); + msg->msnslp_header.length = ntohs(msg->msnslp_header.length); + msg->msnslp_header.flags = ntohs(msg->msnslp_header.flags); + msg->msnslp_header.prev_id = ntohs(msg->msnslp_header.prev_id); + msg->msnslp_header.prev_f9 = ntohs(msg->msnslp_header.prev_f9); + + /* Import the footer. */ + msg->msnslp_footer.app_id = (long)footer; + } g_free(tmp_base); @@ -303,9 +347,53 @@ g_strlcat(str, buf, len); } - g_snprintf(buf, sizeof(buf), "\r\n%s", msn_message_get_body(msg)); + if (msg->msnslp_message) + { + char *c; + char blank[4]; + int session_id, id, offset, total_size, length, flags; + int prev_id, prev_f9, prev_total_size; + + memcpy(blank, 0, 4); + + c = str + strlen(str); + + session_id = htons(msg->msnslp_header.session_id); + id = htons(msg->msnslp_header.id); + offset = htons(msg->msnslp_header.offset); + total_size = htons(msg->msnslp_header.total_size); + length = htons(msg->msnslp_header.length); + flags = htons(msg->msnslp_header.flags); + prev_id = htons(msg->msnslp_header.prev_id); + prev_f9 = htons(msg->msnslp_header.prev_f9); + prev_total_size = htons(msg->msnslp_header.prev_total_size); - g_strlcat(str, buf, len); + memcpy(c, &session_id, 4); c += 4; + memcpy(c, &id, 4); c += 4; + memcpy(c, &offset, 4); c += 4; + memcpy(c, blank, 4); c += 4; + memcpy(c, &total_size, 4); c += 4; + memcpy(c, blank, 4); c += 4; + memcpy(c, &length, 4); c += 4; + memcpy(c, &flags, 4); c += 4; + memcpy(c, &prev_id, 4); c += 4; + memcpy(c, &prev_f9, 4); c += 4; + memcpy(c, &prev_total_size, 4); c += 4; + memcpy(c, blank, 4); c += 4; + + strncpy(c, msn_message_get_body(msg), len); + + c += strlen(msn_message_get_body(msg)); + + memcpy(c, blank, 1); c++; + memcpy(c, &msg->msnslp_footer.app_id, 4); c += 4; + } + else + { + g_snprintf(buf, sizeof(buf), "\r\n%s", msn_message_get_body(msg)); + + g_strlcat(str, buf, len); + } if (msg->size != strlen(msg_start)) { gaim_debug(GAIM_DEBUG_ERROR, "msn", diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/msg.h --- a/src/protocols/msn/msg.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/msg.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -24,6 +24,7 @@ typedef struct _MsnMessage MsnMessage; +#include "msnslp.h" #include "session.h" #include "user.h" @@ -34,6 +35,8 @@ { size_t ref_count; /**< The reference count. */ + gboolean msnslp_message; + MsnUser *sender; MsnUser *receiver; @@ -48,10 +51,15 @@ char *charset; char *body; + MsnSlpHeader msnslp_header; + MsnSlpFooter msnslp_footer; + GHashTable *attr_table; GList *attr_list; }; +#define MSN_MESSAGE(msg) ((MsnMessage *)(msg)) + /** * Creates a new, empty message. * @@ -71,6 +79,8 @@ /** * Destroys a message. + * + * @param msg The message to destroy. */ void msn_message_destroy(MsnMessage *msg); diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/msn.c --- a/src/protocols/msn/msn.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/msn.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -51,7 +51,7 @@ char outparams[MSN_BUF_LEN]; char *alias; - if (entry == NULL || *entry == '\0') + if (entry == NULL || *entry == '\0') alias = g_strdup(""); else alias = g_strdup(entry); @@ -694,7 +694,7 @@ char buf[MSN_BUF_LEN]; if (!strchr(who, '@')) { - g_snprintf(buf, sizeof(buf), + g_snprintf(buf, sizeof(buf), _("An MSN screenname must be in the form \"user@server.com\". " "Perhaps you meant %s@hotmail.com. No changes were made " "to your allow list."), who); @@ -734,7 +734,7 @@ char buf[MSN_BUF_LEN]; if (!strchr(who, '@')) { - g_snprintf(buf, sizeof(buf), + g_snprintf(buf, sizeof(buf), _("An MSN screenname must be in the form \"user@server.com\". " "Perhaps you meant %s@hotmail.com. No changes were made " "to your block list."), who); @@ -1295,7 +1295,6 @@ static void msn_get_info(GaimConnection *gc, const char *name) { - /* MsnSession *session = (MsnSession *)gc->proto_data; */ char url[256]; g_snprintf(url, sizeof url, "%s%s", PROFILE_URL, name); grab_url(url, FALSE, msn_got_info, NULL,"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",1); diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/msn.h --- a/src/protocols/msn/msn.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/msn.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -37,14 +37,15 @@ #include "prpl.h" #include "request.h" #include "server.h" +#include "sslconn.h" #include "util.h" /* XXX */ #include "gaim.h" #ifdef _WIN32 -#include "win32dep.h" -#include "stdint.h" +# include "win32dep.h" +# include "stdint.h" #endif #define MSN_BUF_LEN 8192 @@ -73,4 +74,14 @@ "Chat-Logging: Y\r\n" \ "Buddy-Icons: 1\r\n" + +typedef enum +{ + MSN_LIST_FL_OP = 0x01, + MSN_LIST_AL_OP = 0x02, + MSN_LIST_BL_OP = 0x04, + MSN_LIST_RL_OP = 0x08 + +} MsnListOp; + #endif /* _MSN_H_ */ diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/msnobject.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/msnobject.c Tue Sep 02 04:32:16 2003 +0000 @@ -0,0 +1,225 @@ +/** + * @file msnobject.c MSNObject API + * + * gaim + * + * Copyright (C) 2003 Christian Hammond + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "msnobject.h" + +#define GET_STRING_TAG(field, id) \ + if ((tag = strstr(str, id "=\"")) != NULL) \ + { \ + tag += strlen(id "=\""); \ + c = strchr(tag, '"'); \ + obj->field = g_strndup(tag, tag - c); \ + } + +#define GET_INT_TAG(field, id) \ + if ((tag = strstr(str, id "=\"")) != NULL) \ + { \ + char buf[16]; \ + tag += strlen(id "=\""); \ + c = strchr(tag, '"'); \ + strncpy(buf, tag, tag - c); \ + obj->field = atoi(buf); \ + } + +MsnObject * +msn_object_new(void) +{ + MsnObject *obj; + + obj = g_new0(MsnObject, 1); + + msn_object_set_type(obj, MSN_OBJECT_UNKNOWN); + msn_object_set_friendly(obj, "AAA="); + + return obj; +} + +MsnObject * +msn_object_new_from_string(const char *str) +{ + MsnObject *obj; + char *tag, *c; + + g_return_val_if_fail(str != NULL, NULL); + g_return_val_if_fail(!strncmp(str, "", + msn_object_get_creator(obj), + msn_object_get_size(obj), + msn_object_get_type(obj), + msn_object_get_location(obj), + msn_object_get_friendly(obj), + msn_object_get_sha1d(obj), + msn_object_get_sha1c(obj)); + + return str; +} + +void +msn_object_set_creator(MsnObject *obj, const char *creator) +{ + g_return_if_fail(obj != NULL); + + if (obj->creator != NULL) + g_free(obj->creator); + + obj->creator = (creator == NULL ? NULL : g_strdup(creator)); +} + +void +msn_object_set_size(MsnObject *obj, int size) +{ + g_return_if_fail(obj != NULL); + + obj->size = size; +} + +void +msn_object_set_type(MsnObject *obj, MsnObjectType type) +{ + g_return_if_fail(obj != NULL); + + obj->type = type; +} + +void +msn_object_set_location(MsnObject *obj, const char *location) +{ + g_return_if_fail(obj != NULL); + + if (obj->location != NULL) + g_free(obj->location); + + obj->location = (location == NULL ? NULL : g_strdup(location)); +} + +void +msn_object_set_friendly(MsnObject *obj, const char *friendly) +{ + g_return_if_fail(obj != NULL); + + if (obj->friendly != NULL) + g_free(obj->friendly); + + obj->friendly = (friendly == NULL ? NULL : g_strdup(friendly)); +} + +void +msn_object_set_sha1d(MsnObject *obj, const char *sha1d) +{ + g_return_if_fail(obj != NULL); + + if (obj->sha1d != NULL) + g_free(obj->sha1d); + + obj->sha1d = (sha1d == NULL ? NULL : g_strdup(sha1d)); +} + +void +msn_object_set_sha1c(MsnObject *obj, const char *sha1c) +{ + g_return_if_fail(obj != NULL); + + if (obj->sha1c != NULL) + g_free(obj->sha1c); + + obj->sha1c = (sha1c == NULL ? NULL : g_strdup(sha1c)); +} + +const char * +msn_object_get_creator(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, NULL); + + return obj->creator; +} + +int +msn_object_get_size(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, 0); + + return obj->size; +} + +MsnObjectType +msn_object_get_type(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, MSN_OBJECT_UNKNOWN); + + return obj->type; +} + +const char * +msn_object_get_location(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, NULL); + + return obj->location; +} + +const char * +msn_object_get_friendly(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, NULL); + + return obj->friendly; +} + +const char * +msn_object_get_sha1d(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, NULL); + + return obj->sha1d; +} + +const char * +msn_object_get_sha1c(const MsnObject *obj) +{ + g_return_val_if_fail(obj != NULL, NULL); + + return obj->sha1c; +} diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/msnobject.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/msnobject.h Tue Sep 02 04:32:16 2003 +0000 @@ -0,0 +1,194 @@ +/** + * @file msnobject.h MSNObject API + * + * gaim + * + * Copyright (C) 2003 Christian Hammond + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _MSN_OBJECT_H_ +#define _MSN_OBJECT_H_ + +#include "internal.h" + +typedef enum +{ + MSN_OBJECT_UNKNOWN = -1, /**< Unknown object */ + MSN_OBJECT_RESERVED1 = 1, /**< Reserved */ + MSN_OBJECT_EMOTICON = 2, /**< Custom Emoticon */ + MSN_OBJECT_USERTILE = 3, /**< UserTile (buddy icon) */ + MSN_OBJECT_RESERVED2 = 4, /**< Reserved */ + MSN_OBJECT_BACKGROUND = 5 /**< Background */ + +} MsnObjectType; + +typedef struct +{ + char *creator; + int size; + MsnObjectType type; + char *location; + char *friendly; + char *sha1d; + char *sha1c; + +} MsnObject; + +/** + * Creates a MsnObject structure. + * + * @return A new MsnObject structure. + */ +MsnObject *msn_object_new(void); + +/** + * Creates a MsnObject structure from a string. + * + * @param str The string. + * + * @return The new MsnObject structure. + */ +MsnObject *msn_object_new_from_string(const char *str); + +/** + * Destroys an MsnObject structure. + * + * @param obj The object structure. + */ +void msn_object_destroy(MsnObject *obj); + +/** + * Outputs a string representation of an MsnObject. + * + * @param obj The object. + * + * @return The string representation. This must be freed. + */ +char *msn_object_to_string(const MsnObject *obj); + +/** + * Sets the creator field in a MsnObject. + * + * @param creator The creator value. + */ +void msn_object_set_creator(MsnObject *obj, const char *creator); + +/** + * Sets the size field in a MsnObject. + * + * @param size The size value. + */ +void msn_object_set_size(MsnObject *obj, int size); + +/** + * Sets the type field in a MsnObject. + * + * @param type The type value. + */ +void msn_object_set_type(MsnObject *obj, MsnObjectType type); + +/** + * Sets the location field in a MsnObject. + * + * @param location The location value. + */ +void msn_object_set_location(MsnObject *obj, const char *location); + +/** + * Sets the friendly name field in a MsnObject. + * + * @param friendly The friendly name value. + */ +void msn_object_set_friendly(MsnObject *obj, const char *friendly); + +/** + * Sets the SHA1D field in a MsnObject. + * + * @param sha1d The sha1d value. + */ +void msn_object_set_sha1d(MsnObject *obj, const char *sha1d); + +/** + * Sets the SHA1C field in a MsnObject. + * + * @param sha1c The sha1c value. + */ +void msn_object_set_sha1c(MsnObject *obj, const char *sha1c); + +/** + * Returns a MsnObject's creator value. + * + * @param obj The object. + * + * @return The creator value. + */ +const char *msn_object_get_creator(const MsnObject *obj); + +/** + * Returns a MsnObject's size value. + * + * @param obj The object. + * + * @return The size value. + */ +int msn_object_get_size(const MsnObject *obj); + +/** + * Returns a MsnObject's type. + * + * @param obj The object. + * + * @return The object type. + */ +MsnObjectType msn_object_get_type(const MsnObject *obj); + +/** + * Returns a MsnObject's location value. + * + * @param obj The object. + * + * @return The location value. + */ +const char *msn_object_get_location(const MsnObject *obj); + +/** + * Returns a MsnObject's friendly name value. + * + * @param obj The object. + * + * @return The friendly name value. + */ +const char *msn_object_get_friendly(const MsnObject *obj); + +/** + * Returns a MsnObject's SHA1D value. + * + * @param obj The object. + * + * @return The SHA1D value. + */ +const char *msn_object_get_sha1d(const MsnObject *obj); + +/** + * Returns a MsnObject's SHA1C value. + * + * @param obj The object. + * + * @return The SHA1C value. + */ +const char *msn_object_get_sha1c(const MsnObject *obj); + +#endif /* _MSN_OBJECT_H_ */ diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/msnslp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/msnslp.c Tue Sep 02 04:32:16 2003 +0000 @@ -0,0 +1,53 @@ +/** + * @file msnslp.c MSNSLP support + * + * gaim + * + * Copyright (C) 2003 Christian Hammond + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "msnslp.h" + +MsnSlpSession * +msn_slp_session_new(MsnSwitchBoard *swboard, gboolean local_initiated) +{ + MsnSlpSession *slpsession; + + g_return_val_if_fail(swboard != NULL, NULL); + + slpsession = g_new0(MsnSlpSession, 1); + + slpsession->swboard = swboard; + slpsession->local_initiated = local_initiated; + + return slpsession; +} + +void +msn_slp_session_destroy(MsnSlpSession *session) +{ + g_return_if_fail(session != NULL); + + g_free(session); +} + +void +msn_slp_session_send_msg(MsnSlpSession *session, MsnMessage *msg) +{ + g_return_if_fail(session != NULL); + g_return_if_fail(msg != NULL); + +} diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/msnslp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/msn/msnslp.h Tue Sep 02 04:32:16 2003 +0000 @@ -0,0 +1,86 @@ +/** + * @file msnslp.h MSNSLP support + * + * gaim + * + * Copyright (C) 2003 Christian Hammond + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _MSN_SLP_H_ +#define _MSN_SLP_H_ + +typedef struct +{ + long session_id; + long id; + long offset; + long total_size; + long length; + long flags; + long prev_id; + long prev_f9; + long prev_total_size; + +} MsnSlpHeader; + +typedef struct +{ + long app_id; + +} MsnSlpFooter; + +#include "switchboard.h" + +typedef struct +{ + gboolean local_initiated; + + MsnSwitchBoard *swboard; + + int session_id; + int prev_msg_id; + +} MsnSlpSession; + +/** + * Creates a MSNSLP session. + * + * @param swboard The switchboard. + * @param local_initiated TRUE if the session was initiated locally. + * + * @return The new MSNSLP session handle. + */ +MsnSlpSession *msn_slp_session_new(MsnSwitchBoard *swboard, + gboolean local_initiated); + +/** + * Destroys a MSNSLP session handle. + * + * This does not close the connection. + * + * @param slpsession The MSNSLP session to destroy. + */ +void msn_slp_session_destroy(MsnSlpSession *slpsession); + +/** + * Sends a message over a MSNSLP session. + * + * @param slpsession The MSNSLP session to send the message over. + * @param msg The message to send. + */ +void msn_slp_session_send_msg(MsnSlpSession *session, MsnMessage *msg); + +#endif /* _MSN_SLP_H_ */ diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/notification.c --- a/src/protocols/msn/notification.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/notification.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -42,64 +42,81 @@ add_buddy(MsnServConn *servconn, MsnUser *user) { MsnSession *session = servconn->session; - GaimConnection *gc = session->account->gc; + GaimAccount *account = session->account; + GaimConnection *gc = gaim_account_get_connection(account); GaimBuddy *b; MsnGroup *group = NULL; GaimGroup *g = NULL; - int group_id; + GList *l, *l2; + GSList *buddies; + + buddies = gaim_find_buddies(account, msn_user_get_passport(user)); + + for (l = msn_user_get_group_ids(user); l != NULL; l = l->next) + { + int group_id = GPOINTER_TO_INT(l->data); + GSList *l3; + + if (group_id > -1) + group = msn_groups_find_with_id(session->groups, group_id); - group_id = msn_user_get_group_id(user); + if (group == NULL) + { + gaim_debug(GAIM_DEBUG_WARNING, "msn", + "Group ID %d for user %s was not defined.\n", + group_id, msn_user_get_passport(user)); - if (group_id > -1) - group = msn_groups_find_with_id(session->groups, group_id); + /* Find a group that we can stick this guy into. Lamer. */ + l2 = msn_groups_get_list(session->groups); + + if (l2 != NULL) + { + group = l2->data; + + msn_user_add_group_id(user, msn_group_get_id(group)); + } + } - if (group == NULL) { - GList *l; - gaim_debug(GAIM_DEBUG_WARNING, "msn", - "Group ID %d for user %s was not defined.\n", - group_id, msn_user_get_passport(user)); + if (group == NULL || + (g = gaim_find_group(msn_group_get_name(group))) == NULL) + { + gaim_debug(GAIM_DEBUG_ERROR, "msn", + "Group '%s' appears in server-side " + "buddy list, but not here!", + msn_group_get_name(group)); + } + + if (group != NULL) + msn_group_add_user(group, user); + + b = NULL; + + for (l3 = buddies; l3 != NULL; l3 = l3->next) + { + b = (GaimBuddy *)l3->data; - /* Find a group that we can stick this guy into. Lamer. */ - l = msn_groups_get_list(session->groups); + if (gaim_find_buddys_group(b) == g) + break; + + b = NULL; + } - if (l != NULL) { - group = l->data; + if (b == NULL) + { + b = gaim_buddy_new(account, + msn_user_get_passport(user), NULL); - msn_user_set_group_id(user, msn_group_get_id(group)); + gaim_blist_add_buddy(b, NULL, g, NULL); } + + gaim_debug(GAIM_DEBUG_INFO, "msn", + "Adding MsnUser to %s's proto_data (group %d, %s)\n", + b->name, group_id, (g == NULL ? "(null)" : g->name)); + + b->proto_data = user; } - if (group == NULL || - (g = gaim_find_group(msn_group_get_name(group))) == NULL) { - - gaim_debug(GAIM_DEBUG_ERROR, "msn", - "Group '%s' appears in server-side " - "buddy list, but not here!", - msn_group_get_name(group)); - } - - if (group != NULL) - msn_group_add_user(group, user); - - if (g == NULL) { - /* Should never happen. */ - - if ((g = gaim_find_group(_("Buddies"))) == NULL) { - g = gaim_group_new(_("Buddies")); - gaim_blist_add_group(g, NULL); - } - } - - b = gaim_find_buddy(gc->account, msn_user_get_passport(user)); - - if (b == NULL) { - b = gaim_buddy_new(gc->account, - msn_user_get_passport(user), NULL); - - gaim_blist_add_buddy(b, NULL, g, NULL); - } - - b->proto_data = user; + g_slist_free(buddies); serv_got_alias(gc, (char *)msn_user_get_passport(user), (char *)msn_user_get_name(user)); @@ -107,6 +124,34 @@ return TRUE; } +static size_t +msn_ssl_read(GaimSslConnection *gsc, char **dest_buffer) +{ + size_t size = 0, s; + char *buffer = NULL; + char temp_buf[4096]; + + while ((s = gaim_ssl_read(gsc, temp_buf, sizeof(temp_buf))) > 0) + { + char *new_buffer = g_new(char, size + s + 1); + + if (buffer != NULL) + strncpy(new_buffer, buffer, size); + + g_free(buffer); + buffer = new_buffer; + + strncpy(buffer + size, temp_buf, s); + + buffer[size + s] = '\0'; + + size += s; + } + + *dest_buffer = buffer; + + return size; +} /************************************************************************** * Callbacks @@ -207,29 +252,22 @@ /************************************************************************** * Login **************************************************************************/ + + static gboolean -ver_cmd(MsnServConn *servconn, const char *command, const char **params, +cvr_cmd(MsnServConn *servconn, const char *command, const char **params, size_t param_count) { - GaimConnection *gc = servconn->session->account->gc; - size_t i; - gboolean msnp5_found = FALSE; + GaimAccount *account = servconn->session->account; + GaimConnection *gc = gaim_account_get_connection(account); + char outparams[MSN_BUF_LEN]; - for (i = 1; i < param_count; i++) { - if (!strcmp(params[i], "MSNP5")) { - msnp5_found = TRUE; - break; - } - } + g_snprintf(outparams, sizeof(outparams), + "TWN I %s", gaim_account_get_username(account)); - if (!msnp5_found) { - gaim_connection_error(gc, _("Protocol not supported")); - - return FALSE; - } - - if (!msn_servconn_send_command(servconn, "INF", NULL)) { - gaim_connection_error(gc, _("Unable to request INF")); + if (!msn_servconn_send_command(servconn, "USR", outparams)) + { + gaim_connection_error(gc, _("Unable to request USR\n")); return FALSE; } @@ -248,7 +286,7 @@ if (strcmp(params[1], "MD5")) { gaim_connection_error(gc, _("Unable to login using MD5")); - return FALSE; + return FALSE; } g_snprintf(outparams, sizeof(outparams), "MD5 I %s", @@ -266,6 +304,268 @@ return TRUE; } +static void +login_connect_cb(gpointer data, GaimSslConnection *gsc, + GaimInputCondition cond) +{ + MsnServConn *servconn = (MsnServConn *)data; + MsnSession *session = servconn->session; + GaimConnection *gc = gaim_account_get_connection(session->account); + char *username, *password; + char *request_str; + char *buffer = NULL; + size_t s; + + username = + g_strdup(msn_url_encode(gaim_account_get_username(session->account))); + password = + g_strdup(msn_url_encode(gaim_account_get_password(session->account))); + + request_str = g_strdup_printf( + "GET %s HTTP/1.1\r\n" + "Authorization: Passport1.4 OrgVerb=GET,OrgURL=%s,sign-in=%s,pwd=%s," + "lc=%s,id=%s,tw=%s,fs=%s,ct=%s,kpp=%s,kv=%s,ver=%s,tpf=%s\r\n" + "User-Agent: MSMSGS\r\n" + "Host: %s\r\n" + "Connection: Keep-Alive\r\n" + "Cache-Control: no-cache\r\n" + "\r\n", + session->ssl_login_path, + (char *)g_hash_table_lookup(session->ssl_challenge_data, "ru"), + username, password, + (char *)g_hash_table_lookup(session->ssl_challenge_data, "lc"), + (char *)g_hash_table_lookup(session->ssl_challenge_data, "id"), + (char *)g_hash_table_lookup(session->ssl_challenge_data, "tw"), + (char *)g_hash_table_lookup(session->ssl_challenge_data, "fs"), + (char *)g_hash_table_lookup(session->ssl_challenge_data, "ct"), + (char *)g_hash_table_lookup(session->ssl_challenge_data, "kpp"), + (char *)g_hash_table_lookup(session->ssl_challenge_data, "kv"), + (char *)g_hash_table_lookup(session->ssl_challenge_data, "ver"), + (char *)g_hash_table_lookup(session->ssl_challenge_data, "tpf"), + session->ssl_login_host); + + gaim_debug(GAIM_DEBUG_MISC, "msn", "Sending: {%s}\n", request_str); + + g_free(username); + g_free(password); + + if ((s = gaim_ssl_write(gsc, request_str, strlen(request_str))) <= 0) + { + gaim_connection_error(gc, _("Unable to write to MSN Nexus server.")); + + return; + } + + if ((s = msn_ssl_read(gsc, &buffer)) <= 0) + { + gaim_connection_error(gc, _("Unable to read from MSN Nexus server.")); + + if (buffer != NULL) + g_free(buffer); + + return; + } + + gaim_ssl_close(gsc); + + gaim_debug(GAIM_DEBUG_MISC, "msn", "ssl buffer: {%s}", buffer); + + if (strstr(buffer, "HTTP/1.1 302") != NULL) + { + /* Redirect. */ + char *location, *c; + + if ((location = strstr(buffer, "Location: ")) == NULL) + { + gaim_connection_error(gc, + _("MSN Nexus server returned invalid redirect information.")); + + g_free(buffer); + + return; + } + + location = strchr(location, ' ') + 1; + + if ((c = strchr(location, '\r')) != NULL) + *c = '\0'; + + /* Skip the http:// */ + if ((c = strchr(location, '/')) != NULL) + location = c + 2; + + if ((c = strchr(location, '/')) != NULL) + { + session->ssl_login_path = g_strdup(c); + + *c = '\0'; + } + + session->ssl_login_host = g_strdup(location); + + session->ssl_conn = gaim_ssl_connect(session->account, + session->ssl_login_host, + GAIM_SSL_DEFAULT_PORT, + login_connect_cb, servconn); + } + else if (strstr(buffer, "HTTP/1.1 401 Unauthorized") != NULL) + { + char *error; + + if ((error = strstr(buffer, "WWW-Authenticate")) != NULL) + { + if ((error = strstr(buffer, "cbtxt=")) != NULL) + error += strlen("cbtxt="); + + error = msn_url_decode(error); + } + + + if (error == NULL) + { + gaim_connection_error(gc, + _("Unknown error when attempting to authorize with " + "MSN login server.")); + } + else + gaim_connection_error(gc, error); + } + else + { + char *base, *c; + char outparams[MSN_BUF_LEN]; + + g_free(session->ssl_login_host); + g_free(session->ssl_login_path); + g_hash_table_destroy(session->ssl_challenge_data); + + session->ssl_login_host = NULL; + session->ssl_login_path = NULL; + session->ssl_challenge_data = NULL; + +#if 0 + /* All your base are belong to us. */ + base = buffer; + + /* For great cookie! */ + while ((base = strstr(base, "Set-Cookie: ")) != NULL) + { + base += strlen("Set-Cookie: "); + + c = strchr(base, ';'); + + session->login_cookies = + g_list_append(session->login_cookies, + g_strndup(base, c - base)); + } +#endif + + if ((base = strstr(buffer, "Authentication-Info: ")) == NULL) + { + gaim_debug(GAIM_DEBUG_ERROR, "msn", + "Authentication information was not found. This did " + "not just happen, but if it did, you're screwed. " + "Report this.\n"); + + return; + } + + base = strstr(base, "from-PP='"); + base += strlen("from-PP='"); + c = strchr(base, '\''); + + session->ssl_login_params = g_strndup(base, c - base); + + g_snprintf(outparams, sizeof(outparams), + "TWN S %s", session->ssl_login_params); + + g_free(session->ssl_login_params); + session->ssl_login_params = NULL; + + if (!msn_servconn_send_command(session->notification_conn, "USR", + outparams)) + { + gaim_connection_error(gc, _("Unable to request USR\n")); + } + } + + g_free(buffer); +} + +static void +nexus_connect_cb(gpointer data, GaimSslConnection *gsc, + GaimInputCondition cond) +{ + MsnServConn *servconn = (MsnServConn *)data; + MsnSession *session = servconn->session; + GaimConnection *gc = gaim_account_get_connection(session->account); + char *request_str; + char *da_login; + char *base, *c; + char *buffer = NULL; + size_t s; + + request_str = g_strdup_printf("GET /rdr/pprdr.asp\r\n\r\n"); + + if ((s = gaim_ssl_write(gsc, request_str, strlen(request_str))) <= 0) + { + gaim_connection_error(gc, _("Unable to write to MSN Nexus server.")); + return; + } + + g_free(session->ssl_url); + session->ssl_url = NULL; + + /* Get the PassportURLs line. */ + if ((s = msn_ssl_read(gsc, &buffer)) <= 0) + { + gaim_connection_error(gc, _("Unable to read from MSN Nexus server.")); + + if (buffer != NULL) + g_free(buffer); + + return; + } + + if ((base = strstr(buffer, "PassportURLs")) == NULL) + { + gaim_connection_error(gc, + _("MSN Nexus server returned invalid information.")); + + g_free(buffer); + + return; + } + + if ((da_login = strstr(base, "DALogin=")) != NULL) + { + if ((da_login = strchr(da_login, '=')) != NULL) + da_login++; + + if ((c = strchr(da_login, ',')) != NULL) + *c = '\0'; + + if ((c = strchr(da_login, '/')) != NULL) + { + session->ssl_login_path = g_strdup(c); + + *c = '\0'; + } + + session->ssl_login_host = g_strdup(da_login); + } + + g_free(buffer); + + gaim_ssl_close(gsc); + + /* Now begin the connection to the login server. */ + session->ssl_conn = gaim_ssl_connect(session->account, + session->ssl_login_host, + GAIM_SSL_DEFAULT_PORT, + login_connect_cb, servconn); +} + static gboolean usr_cmd(MsnServConn *servconn, const char *command, const char **params, size_t param_count) @@ -275,8 +575,14 @@ GaimConnection *gc = gaim_account_get_connection(account); char outparams[MSN_BUF_LEN]; - /* We're either getting the challenge or the OK. Let's find out. */ - if (!g_ascii_strcasecmp(params[1], "OK")) { + /* + * We're either getting the passport connect info (if we're on + * MSNP8 or higher), or a challenge request (MSNP7 and lower). + * + * Let's find out. + */ + if (!g_ascii_strcasecmp(params[1], "OK")) + { const char *friendly = msn_url_decode(params[3]); /* OK */ @@ -285,7 +591,8 @@ session->syncing_lists = TRUE; - if (!msn_servconn_send_command(servconn, "SYN", "0")) { + if (!msn_servconn_send_command(servconn, "SYN", "0")) + { gaim_connection_error(gc, _("Unable to write")); return FALSE; @@ -294,7 +601,73 @@ gaim_connection_update_progress(gc, _("Retrieving buddy list"), 7, MSN_CONNECT_STEPS); } - else { + else if (!g_ascii_strcasecmp(params[1], "TWN")) + { + /* Passport authentication */ + char *challenge_data; + char *key, *value = NULL; + char *c; + + if (session->ssl_challenge_data != NULL) + g_hash_table_destroy(session->ssl_challenge_data); + + session->ssl_challenge_data = + g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + + /* Parse the challenge data. */ + + challenge_data = g_strdup(params[3]); + + for (c = challenge_data, key = challenge_data; *c != '\0'; c++) + { + if (*c == '=') + { + *c = '\0'; + + value = c + 1; + } + else if (*c == ',') + { + *c = '\0'; + + g_hash_table_insert(session->ssl_challenge_data, + g_strdup(key), g_strdup(value)); + + key = c + 1; + } + } + +#if 0 + passport_str = g_strdup(msn_url_decode(params[3])); + + for (c = passport_str; *c != '\0'; c++) + { + if (*c == ',') + *c = '&'; + } + + session->ssl_url = passport_str; +#endif + + session->ssl_conn = gaim_ssl_connect(session->account, + "nexus.passport.com", + GAIM_SSL_DEFAULT_PORT, + nexus_connect_cb, servconn); + + if (session->ssl_conn == NULL) + { + gaim_connection_error(gc, + _("Unable to connect to passport server")); + + return FALSE; + } + + gaim_connection_update_progress(gc, _("Password sent"), + 6, MSN_CONNECT_STEPS); + } + else if (!g_ascii_strcasecmp(params[1], "MD5")) + { /* Challenge */ const char *challenge = params[3]; char buf[MSN_BUF_LEN]; @@ -329,6 +702,61 @@ return TRUE; } +static gboolean +ver_cmd(MsnServConn *servconn, const char *command, const char **params, + size_t param_count) +{ + MsnSession *session = servconn->session; + GaimAccount *account = session->account; + GaimConnection *gc = gaim_account_get_connection(account); + gboolean protocol_supported = FALSE; + char outparams[MSN_BUF_LEN]; + char proto_str[8]; + size_t i; + + g_snprintf(proto_str, sizeof(proto_str), "MSNP%d", session->protocol_ver); + + for (i = 1; i < param_count; i++) + { + if (!strcmp(params[i], proto_str)) + { + protocol_supported = TRUE; + break; + } + } + + if (!protocol_supported) { + gaim_connection_error(gc, _("Protocol not supported")); + + return FALSE; + } + + if (session->protocol_ver >= 8) + { + g_snprintf(outparams, sizeof(outparams), + "0x0409 winnt 5.1 i386 MSNMSGR 6.0.0602 MSMSGS %s", + gaim_account_get_username(account)); + + if (!msn_servconn_send_command(servconn, "CVR", outparams)) + { + gaim_connection_error(gc, _("Unable to request CVR\n")); + + return FALSE; + } + } + else + { + if (!msn_servconn_send_command(servconn, "INF", NULL)) + { + gaim_connection_error(gc, _("Unable to request INF\n")); + + return FALSE; + } + } + + return TRUE; +} + /************************************************************************** * Log out **************************************************************************/ @@ -378,22 +806,37 @@ chl_cmd(MsnServConn *servconn, const char *command, const char **params, size_t param_count) { - GaimConnection *gc = servconn->session->account->gc; + MsnSession *session = servconn->session; + GaimConnection *gc = session->account->gc; char buf[MSN_BUF_LEN]; char buf2[3]; + const char *challenge_resp; md5_state_t st; md5_byte_t di[16]; int i; md5_init(&st); md5_append(&st, (const md5_byte_t *)params[1], strlen(params[1])); - md5_append(&st, (const md5_byte_t *)"Q1P7W2E4J9R8U3S5", - strlen("Q1P7W2E4J9R8U3S5")); + + if (session->protocol_ver >= 8) + { + challenge_resp = "VT6PX?UQTM4WM%YR"; + } + else + { + challenge_resp = "Q1P7W2E4J9R8U3S5"; + } + + md5_append(&st, (const md5_byte_t *)challenge_resp, + strlen(challenge_resp)); md5_finish(&st, di); g_snprintf(buf, sizeof(buf), - "QRY %u msmsgs@msnmsgr.com 32\r\n", - servconn->session->trId++); + "QRY %u %s 32\r\n", + servconn->session->trId++, + (session->protocol_ver >= 8 + ? "PROD0038W!61ZTF9" + : "msmsgs@msnmsgr.com")); for (i = 0; i < 16; i++) { g_snprintf(buf2, sizeof(buf2), "%02x", di[i]); @@ -435,7 +878,7 @@ user = msn_user_new(session, passport, NULL); if (group_id != NULL) - msn_user_set_group_id(user, atoi(group_id)); + msn_user_add_group_id(user, atoi(group_id)); add_buddy(servconn, user); @@ -491,8 +934,14 @@ size_t param_count) { GaimConnection *gc = servconn->session->account->gc; + const char *list_name; - if (!g_ascii_strcasecmp(params[2], "AL")) { + if (servconn->session->protocol_ver >= 8) + list_name = params[0]; + else + list_name = params[2]; + + if (!g_ascii_strcasecmp(list_name, "AL")) { /* * If the current setting is AL, messages from users who * are not in BL will be delivered. @@ -523,13 +972,21 @@ GaimBuddy *b; MsnUser *user; - if (param_count < 4) + if (param_count == 4) + { + passport = params[1]; + type = params[2]; + value = params[3]; + } + else if (param_count == 2) + { + passport = msn_user_get_passport(session->last_user_added); + type = params[0]; + value = params[1]; + } + else return TRUE; - passport = params[1]; - type = params[2]; - value = params[3]; - user = msn_users_find_with_passport(session->users, passport); if (value != NULL) { @@ -627,18 +1084,25 @@ MsnGroup *group; GaimGroup *g; const char *name; - int group_num, num_groups, group_id; + int num_groups, group_id; - group_num = atoi(params[2]); - num_groups = atoi(params[3]); - group_id = atoi(params[4]); - name = msn_url_decode(params[5]); + if (session->protocol_ver >= 8) + { + group_id = atoi(params[0]); + name = msn_url_decode(params[1]); + } + else + { + num_groups = atoi(params[3]); + group_id = atoi(params[4]); + name = msn_url_decode(params[5]); - if (num_groups == 0) - return TRUE; + if (num_groups == 0) + return TRUE; - if (!strcmp(name, "~")) - name = _("Buddies"); + if (!strcmp(name, "~")) + name = _("Buddies"); + } group = msn_group_new(session, group_id, name); @@ -657,79 +1121,86 @@ size_t param_count) { MsnSession *session = servconn->session; - GaimConnection *gc = session->account->gc; - int user_num; - int num_users; - const char *type; + GaimAccount *account = session->account; + GaimConnection *gc = gaim_account_get_connection(account); const char *passport = NULL; const char *friend = NULL; - type = params[1]; - user_num = atoi(params[3]); - num_users = atoi(params[4]); - - if (g_ascii_strcasecmp(type, "RL") && user_num == 0 && num_users == 0) - return TRUE; /* There are no users on this list. */ + if (session->protocol_ver >= 8) + { + const char *group_nums; + int list_op; - if (num_users > 0) { - passport = params[5]; - friend = msn_url_decode(params[6]); - } + passport = params[0]; + friend = msn_url_decode(params[1]); + list_op = atoi(params[2]); + group_nums = params[3]; - if (session->syncing_lists && session->lists_synced) - return TRUE; + if (list_op & MSN_LIST_FL_OP) + { + MsnUser *user; + char **c; + char **tokens; + + user = msn_user_new(session, passport, friend); - if (!g_ascii_strcasecmp(type, "FL") && user_num != 0) { - /* These are users on our contact list. */ - MsnUser *user; - - user = msn_user_new(session, passport, friend); - - if (param_count == 8) - msn_user_set_group_id(user, atoi(params[7])); + tokens = g_strsplit(group_nums, ",", -1); - session->lists.forward = g_slist_append(session->lists.forward, user); - } - else if (!g_ascii_strcasecmp(type, "AL") && user_num != 0) { - /* These are users who are allowed to see our status. */ - if (g_slist_find_custom(gc->account->deny, passport, - (GCompareFunc)strcmp)) { + gaim_debug(GAIM_DEBUG_MISC, "msn", + "Fetching group IDs from '%s'\n", group_nums); + for (c = tokens; *c != NULL; c++) + { + gaim_debug(GAIM_DEBUG_MISC, "msn", + "Appending group ID %d\n", atoi(*c)); + msn_user_add_group_id(user, atoi(*c)); + } - gaim_debug(GAIM_DEBUG_INFO, "msn", - "Moving user from deny list to permit: %s (%s)\n", - passport, friend); + g_strfreev(tokens); - gaim_privacy_deny_remove(gc->account, passport, TRUE); + session->lists.forward = + g_slist_append(session->lists.forward, user); + + session->last_user_added = user; } - gaim_privacy_permit_add(gc->account, passport, TRUE); - } - else if (!g_ascii_strcasecmp(type, "BL") && user_num != 0) { - /* These are users who are not allowed to see our status. */ - gaim_privacy_deny_add(gc->account, passport, TRUE); - } - else if (!g_ascii_strcasecmp(type, "RL")) { - /* These are users who have us on their contact list. */ - if (user_num > 0) { + if (list_op & MSN_LIST_AL_OP) + { + /* These are users who are allowed to see our status. */ + + if (g_slist_find_custom(account->deny, passport, + (GCompareFunc)strcmp)) + { + gaim_privacy_deny_remove(gc->account, passport, TRUE); + } + + gaim_privacy_permit_add(account, passport, TRUE); + } + + if (list_op & MSN_LIST_BL_OP) + { + /* These are users who are not allowed to see our status. */ + gaim_privacy_deny_add(account, passport, TRUE); + } + + if (list_op & MSN_LIST_RL_OP) + { + /* These are users who have us on their contact list. */ + gboolean new_entry = TRUE; - if (g_slist_find_custom(gc->account->permit, passport, - (GCompareFunc)g_ascii_strcasecmp)) { - new_entry = FALSE; - } - - if (g_slist_find_custom(gc->account->deny, passport, - (GCompareFunc)g_ascii_strcasecmp)) { + if (g_slist_find_custom(account->permit, passport, + (GCompareFunc)g_ascii_strcasecmp) || + g_slist_find_custom(account->deny, passport, + (GCompareFunc)g_ascii_strcasecmp)) + { new_entry = FALSE; } - if (new_entry) { + if (new_entry) + { MsnPermitAdd *pa; char msg[MSN_BUF_LEN]; - gaim_debug(GAIM_DEBUG_WARNING, "msn", - "Unresolved MSN RL entry: %s\n", passport); - pa = g_new0(MsnPermitAdd, 1); pa->user = msn_user_new(session, passport, friend); pa->gc = gc; @@ -748,12 +1219,12 @@ } } - if (user_num != num_users) - return TRUE; /* This isn't the last one in the RL. */ + session->num_users++; - /* Now we're at the last one, so we can do final work. */ - if (!session->lists_synced) { - if (!msn_servconn_send_command(servconn, "CHG", "NLN")) { + if (session->num_users == session->total_users) + { + if (!msn_servconn_send_command(servconn, "CHG", "NLN")) + { gaim_connection_error(gc, _("Unable to write")); return FALSE; @@ -761,31 +1232,178 @@ gaim_connection_set_state(gc, GAIM_CONNECTED); serv_finish_login(gc); + + if (session->lists.allow == NULL) + session->lists.allow = g_slist_copy(account->permit); + else + session->lists.allow = g_slist_concat(session->lists.allow, + account->permit); + + if (session->lists.block == NULL) + session->lists.block = g_slist_copy(account->permit); + else + session->lists.block = g_slist_concat(session->lists.block, + account->deny); + + while (session->lists.forward != NULL) + { + MsnUser *user = session->lists.forward->data; + + session->lists.forward = + g_slist_remove(session->lists.forward, user); + + add_buddy(servconn, user); + } + + session->syncing_lists = FALSE; + session->lists_synced = TRUE; + } + } + else + { + const char *list_name; + int user_num; + int num_users; + + list_name = params[1]; + user_num = atoi(params[3]); + num_users = atoi(params[4]); + + if (g_ascii_strcasecmp(list_name, "RL") && + user_num == 0 && num_users == 0) + { + return TRUE; /* There are no users on this list. */ + } + + if (num_users > 0) + { + passport = params[5]; + friend = msn_url_decode(params[6]); } - if (session->lists.allow == NULL) - session->lists.allow = g_slist_copy(gc->account->permit); - else - session->lists.allow = g_slist_concat(session->lists.allow, - gc->account->permit); + if (session->syncing_lists && session->lists_synced) + return TRUE; + + if (!g_ascii_strcasecmp(list_name, "FL") && user_num != 0) + { + /* These are users on our contact list. */ + MsnUser *user; + + user = msn_user_new(session, passport, friend); + + if (param_count == 8) + msn_user_add_group_id(user, atoi(params[7])); + + session->lists.forward = + g_slist_append(session->lists.forward, user); + } + else if (!g_ascii_strcasecmp(list_name, "AL") && user_num != 0) + { + /* These are users who are allowed to see our status. */ + if (g_slist_find_custom(gc->account->deny, passport, + (GCompareFunc)strcmp)) + { + gaim_debug(GAIM_DEBUG_INFO, "msn", + "Moving user from deny list to permit: %s (%s)\n", + passport, friend); + + gaim_privacy_deny_remove(gc->account, passport, TRUE); + } - if (session->lists.block == NULL) - session->lists.block = g_slist_copy(gc->account->deny); - else - session->lists.block = g_slist_concat(session->lists.block, - gc->account->deny); + gaim_privacy_permit_add(gc->account, passport, TRUE); + } + else if (!g_ascii_strcasecmp(list_name, "BL") && user_num != 0) + { + /* These are users who are not allowed to see our status. */ + gaim_privacy_deny_add(gc->account, passport, TRUE); + } + else if (!g_ascii_strcasecmp(list_name, "RL")) + { + /* These are users who have us on their contact list. */ + if (user_num > 0) + { + gboolean new_entry = TRUE; + + if (g_slist_find_custom(gc->account->permit, passport, + (GCompareFunc)g_ascii_strcasecmp)) + { + new_entry = FALSE; + } + + if (g_slist_find_custom(gc->account->deny, passport, + (GCompareFunc)g_ascii_strcasecmp)) + { + new_entry = FALSE; + } + + if (new_entry) + { + MsnPermitAdd *pa; + char msg[MSN_BUF_LEN]; - while (session->lists.forward != NULL) { - MsnUser *user = session->lists.forward->data; + gaim_debug(GAIM_DEBUG_WARNING, "msn", + "Unresolved MSN RL entry: %s\n", passport); + + pa = g_new0(MsnPermitAdd, 1); + pa->user = msn_user_new(session, passport, friend); + pa->gc = gc; + + g_snprintf(msg, sizeof(msg), + _("The user %s (%s) wants to add you to their " + "buddy list."), + msn_user_get_passport(pa->user), + msn_user_get_name(pa->user)); - session->lists.forward = g_slist_remove(session->lists.forward, - user); + gaim_request_action(gc, NULL, msg, NULL, 0, pa, 2, + _("Authorize"), + G_CALLBACK(msn_accept_add_cb), + _("Deny"), + G_CALLBACK(msn_cancel_add_cb)); + } + } + + if (user_num != num_users) + return TRUE; /* This isn't the last one in the RL. */ + + /* Now we're at the last one, so we can do final work. */ + if (!session->lists_synced) + { + if (!msn_servconn_send_command(servconn, "CHG", "NLN")) + { + gaim_connection_error(gc, _("Unable to write")); - add_buddy(servconn, user); - } + return FALSE; + } + + gaim_connection_set_state(gc, GAIM_CONNECTED); + serv_finish_login(gc); + } + + if (session->lists.allow == NULL) + session->lists.allow = g_slist_copy(gc->account->permit); + else + session->lists.allow = g_slist_concat(session->lists.allow, + gc->account->permit); - session->syncing_lists = FALSE; - session->lists_synced = TRUE; + if (session->lists.block == NULL) + session->lists.block = g_slist_copy(gc->account->deny); + else + session->lists.block = g_slist_concat(session->lists.block, + gc->account->deny); + + while (session->lists.forward != NULL) + { + MsnUser *user = session->lists.forward->data; + + session->lists.forward = + g_slist_remove(session->lists.forward, user); + + add_buddy(servconn, user); + } + + session->syncing_lists = FALSE; + session->lists_synced = TRUE; + } } return TRUE; @@ -987,6 +1605,21 @@ return TRUE; } +static gboolean +syn_cmd(MsnServConn *servconn, const char *command, const char **params, + size_t param_count) +{ + MsnSession *session = servconn->session; + + if (session->protocol_ver >= 8) + { + session->total_users = atoi(params[2]); + session->total_groups = atoi(params[3]); + } + + return TRUE; +} + /************************************************************************** * Misc commands **************************************************************************/ @@ -1239,6 +1872,12 @@ if ((value = msn_message_get_attr(msg, "MSPAuth")) != NULL) session->passport_info.mspauth = g_strdup(value); + if ((value = msn_message_get_attr(msg, "ClientIP")) != NULL) + session->passport_info.client_ip = g_strdup(value); + + if ((value = msn_message_get_attr(msg, "ClientPort")) != NULL) + session->passport_info.client_port = ntohs(atoi(value)); + return TRUE; } @@ -1347,7 +1986,7 @@ "signed out at that time. Please finish any " "conversations in progress.\n\nAfter the " "maintenance has been completed, you will be " - "able to successfully sign in.", + "able to successfully sign in.", "The MSN server will shut down for maintenance " "in %d minutes. You will automatically be " "signed out at that time. Please finish any " @@ -1375,6 +2014,8 @@ MsnSession *session = notification->session; GaimAccount *account = session->account; GaimConnection *gc = gaim_account_get_connection(account); + char proto_vers[256]; + size_t i; if (source == -1) { gaim_connection_error(session->account->gc, _("Unable to connect")); @@ -1384,8 +2025,21 @@ if (notification->fd != source) notification->fd = source; - if (!msn_servconn_send_command(notification, "VER", - "MSNP7 MSNP6 MSNP5 MSNP4 CVR0")) { + proto_vers[0] = '\0'; + + for (i = session->protocol_ver; i >= 7; i--) + { + char old_buf[256]; + + strcpy(old_buf, proto_vers); + + g_snprintf(proto_vers, sizeof(proto_vers), "MSNP%d %s", i, old_buf); + } + + strncat(proto_vers, "CVR0", sizeof(proto_vers)); + + if (!msn_servconn_send_command(notification, "VER", proto_vers)) + { gaim_connection_error(gc, _("Unable to write to server")); return FALSE; } @@ -1429,6 +2083,7 @@ msn_servconn_register_command(notification, "BPR", bpr_cmd); msn_servconn_register_command(notification, "CHG", blank_cmd); msn_servconn_register_command(notification, "CHL", chl_cmd); + msn_servconn_register_command(notification, "CVR", cvr_cmd); msn_servconn_register_command(notification, "FLN", fln_cmd); msn_servconn_register_command(notification, "GTC", blank_cmd); msn_servconn_register_command(notification, "ILN", iln_cmd); @@ -1448,7 +2103,7 @@ msn_servconn_register_command(notification, "REM", rem_cmd); msn_servconn_register_command(notification, "RMG", rmg_cmd); msn_servconn_register_command(notification, "RNG", rng_cmd); - msn_servconn_register_command(notification, "SYN", blank_cmd); + msn_servconn_register_command(notification, "SYN", syn_cmd); msn_servconn_register_command(notification, "URL", url_cmd); msn_servconn_register_command(notification, "USR", usr_cmd); msn_servconn_register_command(notification, "VER", ver_cmd); diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/notification.h --- a/src/protocols/msn/notification.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/notification.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/page.c --- a/src/protocols/msn/page.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/page.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/page.h --- a/src/protocols/msn/page.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/page.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/servconn.c --- a/src/protocols/msn/servconn.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/servconn.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/servconn.h --- a/src/protocols/msn/servconn.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/servconn.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -22,6 +22,8 @@ #ifndef _MSN_SERVCONN_H_ #define _MSN_SERVCONN_H_ +#include "proxy.h" + typedef struct _MsnServConn MsnServConn; #include "msg.h" diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/session.c --- a/src/protocols/msn/session.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/session.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -39,6 +39,8 @@ session->users = msn_users_new(); session->groups = msn_groups_new(); + session->protocol_ver = 9; + return session; } diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/session.h --- a/src/protocols/msn/session.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/session.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -24,6 +24,8 @@ typedef struct _MsnSession MsnSession; +#include "sslconn.h" + #include "servconn.h" #include "switchboard.h" #include "user.h" @@ -34,6 +36,8 @@ GaimAccount *account; MsnUser *user; + int protocol_ver; + char *dispatch_server; int dispatch_port; @@ -44,6 +48,13 @@ unsigned int trId; + char *ssl_url; + char *ssl_login_host; + char *ssl_login_path; + char *ssl_login_params; + GHashTable *ssl_challenge_data; + GaimSslConnection *ssl_conn; + MsnUsers *users; MsnGroups *groups; @@ -66,12 +77,22 @@ char *mspauth; unsigned long sl; char *file; + char *client_ip; + int client_port; } passport_info; /* You have no idea how much I hate all that is below. */ GaimPlugin *prpl; + /* For MSNP8 and MSNP9. */ + int num_users; + int total_users; + int num_groups; + int total_groups; + MsnUser *last_user_added; + + /* For MSNP7 and lower. */ gboolean syncing_lists; gboolean lists_synced; diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/state.c --- a/src/protocols/msn/state.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/state.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/state.h --- a/src/protocols/msn/state.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/state.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/switchboard.h --- a/src/protocols/msn/switchboard.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/switchboard.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -24,6 +24,8 @@ typedef struct _MsnSwitchBoard MsnSwitchBoard; +#include "conversation.h" + #include "servconn.h" #include "msg.h" #include "user.h" diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/user.c --- a/src/protocols/msn/user.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/user.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -35,7 +35,6 @@ user->session = session; msn_user_set_passport(user, passport); - msn_user_set_group_id(user, -1); msn_users_add(session->users, user); } @@ -65,6 +64,9 @@ if (user->clientcaps != NULL) g_hash_table_destroy(user->clientcaps); + if (user->group_ids != NULL) + g_list_free(user->group_ids); + if (user->passport != NULL) g_free(user->passport); if (user->name != NULL) g_free(user->name); @@ -127,14 +129,32 @@ } void -msn_user_set_group_id(MsnUser *user, int id) +msn_user_set_group_ids(MsnUser *user, GList *ids) { g_return_if_fail(user != NULL); - user->group_id = id; + user->group_ids = ids; } void +msn_user_add_group_id(MsnUser *user, int id) +{ + g_return_if_fail(user != NULL); + g_return_if_fail(id > -1); + + if (!g_list_find(user->group_ids, GINT_TO_POINTER(id))) + user->group_ids = g_list_append(user->group_ids, GINT_TO_POINTER(id)); +} + +void +msn_user_remove_group_id(MsnUser *user, int id) +{ + g_return_if_fail(user != NULL); + g_return_if_fail(id > -1); + + user->group_ids = g_list_remove(user->group_ids, GINT_TO_POINTER(id)); +} +void msn_user_set_home_phone(MsnUser *user, const char *number) { g_return_if_fail(user != NULL); @@ -184,12 +204,12 @@ return user->name; } -int -msn_user_get_group_id(const MsnUser *user) +GList * +msn_user_get_group_ids(const MsnUser *user) { - g_return_val_if_fail(user != NULL, -1); + g_return_val_if_fail(user != NULL, NULL); - return user->group_id; + return user->group_ids; } const char * diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/user.h --- a/src/protocols/msn/user.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/user.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -47,7 +47,7 @@ gboolean mobile; /**< Signed up with MSN Mobile. */ - int group_id; /**< The group ID. */ + GList *group_ids; /**< The group IDs. */ size_t ref_count; /**< The reference count. */ @@ -71,7 +71,7 @@ /** * Creates a new user structure. - * + * * @param session The MSN session. * @param passport The initial passport. * @param name The initial friendly name. @@ -125,12 +125,28 @@ void msn_user_set_name(MsnUser *user, const char *name); /** - * Sets the group ID for a user. + * Sets the group ID list for a user. + * + * @param user The user. + * @param ids The group ID list. + */ +void msn_user_set_group_ids(MsnUser *user, GList *ids); + +/** + * Adds the group ID for a user. * * @param user The user. * @param id The group ID. */ -void msn_user_set_group_id(MsnUser *user, int id); +void msn_user_add_group_id(MsnUser *user, int id); + +/** + * Removes the group ID from a user. + * + * @param user The user. + * @param id The group ID. + */ +void msn_user_remove_group_id(MsnUser *user, int id); /** * Sets the home phone number for a user. @@ -175,13 +191,13 @@ const char *msn_user_get_name(const MsnUser *user); /** - * Returns the group ID for a user. + * Returns the group IDs for a user. * * @param user The user. * - * @return The group ID. + * @return The group IDs. */ -int msn_user_get_group_id(const MsnUser *user); +GList *msn_user_get_group_ids(const MsnUser *user); /** * Returns the home phone number for a user. @@ -268,7 +284,7 @@ * Returns the number of users in a users list. * * @param users The users list. - * + * * @return The number of users. */ size_t msn_users_get_count(const MsnUsers *users); diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/utils.c --- a/src/protocols/msn/utils.c Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/utils.c Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or diff -r 57161e3abbb5 -r b7e113a59b51 src/protocols/msn/utils.h --- a/src/protocols/msn/utils.h Tue Sep 02 04:28:34 2003 +0000 +++ b/src/protocols/msn/utils.h Tue Sep 02 04:32:16 2003 +0000 @@ -4,7 +4,7 @@ * gaim * * Copyright (C) 2003 Christian Hammond - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or