Changes in / [f1cea66:560d0a0]


Ignore:
Files:
6 added
14 deleted
40 edited

Legend:

Unmodified
Added
Removed
  • Makefile

    rf1cea66 r560d0a0  
    1010
    1111# Program variables
    12 objects = bitlbee.o dcc.o help.o ipc.o irc.o irc_im.o irc_channel.o irc_commands.o irc_send.o irc_user.o irc_util.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS)
    13 headers = account.h bitlbee.h commands.h conf.h config.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/ftutil.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/ft.h protocols/nogaim.h
     12objects = account.o bitlbee.o chat.o dcc.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o
     13headers = account.h bitlbee.h commands.h conf.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/ftutil.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/ft.h protocols/nogaim.h
    1414subdirs = lib protocols
    1515
  • bitlbee.h

    rf1cea66 r560d0a0  
    126126#define CONF_FILE_DEF ETCDIR "bitlbee.conf"
    127127
    128 #include "bee.h"
    129128#include "irc.h"
    130129#include "storage.h"
     
    161160gboolean bitlbee_io_current_client_write( gpointer data, gint source, b_input_condition cond );
    162161
    163 void root_command_string( irc_t *irc, char *command );
     162void root_command_string( irc_t *irc, user_t *u, char *command, int flags );
    164163void root_command( irc_t *irc, char *command[] );
    165164gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond );
  • conf.c

    rf1cea66 r560d0a0  
    376376                if( g_strcasecmp( ini->section, "defaults" ) == 0 )
    377377                {
    378                         set_t *s = set_find( &irc->b->set, ini->key );
     378                        set_t *s = set_find( &irc->set, ini->key );
    379379                       
    380380                        if( s )
  • configure

    rf1cea66 r560d0a0  
    2727yahoo=1
    2828twitter=1
    29 twitter=1
    3029purple=0
    3130
     
    6968--oscar=0/1     Disable/enable Oscar part (ICQ, AIM)    $oscar
    7069--yahoo=0/1     Disable/enable Yahoo part               $yahoo
    71 --twitter=0/1   Disable/enable Twitter part             $twitter
     70--twitter=0/1 Disable/enable Twitter part               $twitter
    7271
    7372--purple=0/1    Disable/enable libpurple support        $purple
  • dcc.c

    rf1cea66 r560d0a0  
    6161unsigned int receivedchunks=0, receiveddata=0;
    6262
    63 void dcc_finish( file_transfer_t *file );
    64 void dcc_close( file_transfer_t *file );
     63static void dcc_finish( file_transfer_t *file );
     64static void dcc_close( file_transfer_t *file );
    6565gboolean dccs_send_proto( gpointer data, gint fd, b_input_condition cond );
    66 int dccs_send_request( struct dcc_file_transfer *df, irc_user_t *iu, struct sockaddr_storage *saddr );
     66int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct sockaddr_storage *saddr );
     67gboolean dccs_recv_start( file_transfer_t *ft );
    6768gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond);
    6869gboolean dccs_recv_write_request( file_transfer_t *ft );
     
    7071gboolean dcc_abort( dcc_file_transfer_t *df, char *reason, ... );
    7172
    72 dcc_file_transfer_t *dcc_alloc_transfer( const char *file_name, size_t file_size, struct im_connection *ic )
     73/* As defined in ft.h */
     74file_transfer_t *imcb_file_send_start( struct im_connection *ic, char *handle, char *file_name, size_t file_size )
     75{
     76        user_t *u = user_findhandle( ic, handle );
     77        /* one could handle this more intelligent like imcb_buddy_msg.
     78         * can't call it directly though cause it does some wrapping.
     79         * Maybe give imcb_buddy_msg a parameter NO_WRAPPING? */
     80        if (!u) return NULL;
     81
     82        return dccs_send_start( ic, u->nick, file_name, file_size );
     83};
     84
     85/* As defined in ft.h */
     86void imcb_file_canceled( file_transfer_t *file, char *reason )
     87{
     88        if( file->canceled )
     89                file->canceled( file, reason );
     90
     91        dcc_close( file );
     92}
     93
     94/* As defined in ft.h */
     95gboolean imcb_file_recv_start( file_transfer_t *ft )
     96{
     97        return dccs_recv_start( ft );
     98}
     99
     100/* As defined in ft.h */
     101void imcb_file_finished( file_transfer_t *file )
     102{
     103        dcc_file_transfer_t *df = file->priv;
     104
     105        if( file->bytes_transferred >= file->file_size )
     106                dcc_finish( file );
     107        else
     108                df->proto_finished = TRUE;
     109}
     110
     111dcc_file_transfer_t *dcc_alloc_transfer( char *file_name, size_t file_size, struct im_connection *ic )
    73112{
    74113        file_transfer_t *file = g_new0( file_transfer_t, 1 );
     
    78117        file->file_name = g_strdup( file_name );
    79118        file->local_id = local_transfer_id++;
    80         file->ic = df->ic = ic;
     119        df->ic = ic;
    81120        df->ft = file;
    82121       
     
    85124
    86125/* This is where the sending magic starts... */
    87 file_transfer_t *dccs_send_start( struct im_connection *ic, irc_user_t *iu, const char *file_name, size_t file_size )
     126file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, char *file_name, size_t file_size )
    88127{
    89128        file_transfer_t *file;
    90129        dcc_file_transfer_t *df;
    91         irc_t *irc = (irc_t *) ic->bee->ui_data;
    92130        struct sockaddr_storage saddr;
    93131        char *errmsg;
     
    112150        file->status = FT_STATUS_LISTENING;
    113151
    114         if( !dccs_send_request( df, iu, &saddr ) )
     152        if( !dccs_send_request( df, user_nick, &saddr ) )
    115153                return NULL;
    116154
     
    118156        df->watch_in = b_input_add( df->fd, B_EV_IO_READ, dccs_send_proto, df );
    119157
    120         irc->file_transfers = g_slist_prepend( irc->file_transfers, file );
     158        df->ic->irc->file_transfers = g_slist_prepend( df->ic->irc->file_transfers, file );
    121159
    122160        df->progress_timeout = b_timeout_add( DCC_MAX_STALL * 1000, dcc_progress, df );
     
    125163                      "Accept the file transfer if you'd like the file. If you don't, "
    126164                      "issue the 'transfers reject' command.",
    127                       iu->nick, file_name, file_size / 1024 );
     165                      user_nick, file_name, file_size / 1024 );
    128166
    129167        return file;
     
    178216
    179217/* Creates the "DCC SEND" line and sends it to the server */
    180 int dccs_send_request( struct dcc_file_transfer *df, irc_user_t *iu, struct sockaddr_storage *saddr )
     218int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct sockaddr_storage *saddr )
    181219{
    182220        char ipaddr[INET6_ADDRSTRLEN];
     
    212250                                df->ft->file_name, ipaddr, port, df->ft->file_size );
    213251       
    214         irc_send_msg_raw( iu, "PRIVMSG", iu->irc->user->nick, cmd );
     252        if ( !irc_msgfrom( df->ic->irc, user_nick, cmd ) )
     253                return dcc_abort( df, "Couldn't send `DCC SEND' message to %s.", user_nick );
    215254
    216255        g_free( cmd );
     
    457496 * Cleans up after a transfer.
    458497 */
    459 void dcc_close( file_transfer_t *file )
     498static void dcc_close( file_transfer_t *file )
    460499{
    461500        dcc_file_transfer_t *df = file->priv;
    462         irc_t *irc = (irc_t *) df->ic->bee->ui_data;
    463501
    464502        if( file->free )
     
    476514                b_event_remove( df->progress_timeout );
    477515       
    478         irc->file_transfers = g_slist_remove( irc->file_transfers, file );
     516        df->ic->irc->file_transfers = g_slist_remove( df->ic->irc->file_transfers, file );
    479517       
    480518        g_free( df );
     
    504542 *
    505543 */
    506 file_transfer_t *dcc_request( struct im_connection *ic, char* const* ctcp )
    507 {
    508         irc_t *irc = (irc_t *) ic->bee->ui_data;
     544file_transfer_t *dcc_request( struct im_connection *ic, char *line )
     545{
     546        char *pattern = "SEND"
     547                " (([^\"][^ ]*)|\"(([^\"]|\\\")*)\")"
     548                " (([0-9]*)|([^ ]*))"
     549                " ([0-9]*)"
     550                " ([0-9]*)\001";
     551        regmatch_t pmatch[10];
     552        regex_t re;
    509553        file_transfer_t *ft;
    510554        dcc_file_transfer_t *df;
    511         int gret;
    512         size_t filesize;
    513        
    514         if( ctcp[5] != NULL &&
    515             sscanf( ctcp[4], "%zd", &filesize ) == 1 && /* Just int. validation. */
    516             sscanf( ctcp[5], "%zd", &filesize ) == 1 )
    517         {
     555        char errbuf[256];
     556        int regerrcode, gret;
     557
     558        if( ( regerrcode = regcomp( &re, pattern, REG_EXTENDED ) ) ||
     559            ( regerrcode = regexec( &re, line, 10, pmatch, 0 ) ) ) {
     560                regerror( regerrcode,&re,errbuf,sizeof( errbuf ) );
     561                imcb_log( ic,
     562                          "DCC: error parsing 'DCC SEND': %s, line: %s",
     563                          errbuf, line );
     564                return NULL;
     565        }
     566
     567        if( ( pmatch[1].rm_so > 0 ) &&
     568            ( pmatch[5].rm_so > 0 ) &&
     569            ( pmatch[8].rm_so > 0 ) &&
     570            ( pmatch[9].rm_so > 0 ) )
     571        {
     572                char *input = g_strdup( line );
    518573                char *filename, *host, *port;
     574                size_t filesize;
    519575                struct addrinfo hints, *rp;
    520                
    521                 filename = ctcp[2];
    522                
    523                 host = ctcp[3];
    524                 while( *host && isdigit( *host ) ) host++; /* Just digits? */
    525                 if( *host == '\0' )
     576
     577                /* "filename" or filename */
     578                if ( pmatch[2].rm_so > 0 )
    526579                {
    527                         struct in_addr ipaddr = { .s_addr = htonl( atoll( ctcp[3] ) ) };
     580                        input[pmatch[2].rm_eo] = '\0';
     581                        filename = input + pmatch[2].rm_so;
     582                } else
     583                {
     584                        input[pmatch[3].rm_eo] = '\0';
     585                        filename = input + pmatch[3].rm_so;
     586                }
     587                       
     588                input[pmatch[5].rm_eo] = '\0';
     589
     590                /* number means ipv4, something else means ipv6 */
     591                if ( pmatch[6].rm_so > 0 )
     592                {
     593                        struct in_addr ipaddr = { .s_addr = htonl( strtoul( input + pmatch[5].rm_so, NULL, 10 ) ) };
    528594                        host = inet_ntoa( ipaddr );
    529595                } else
    530596                {
    531597                        /* Contains non-numbers, hopefully an IPV6 address */
    532                         host = ctcp[3];
     598                        host = input + pmatch[7].rm_so;
    533599                }
    534600
    535                 port = ctcp[4];
    536                 filesize = atoll( ctcp[5] );
     601                input[pmatch[8].rm_eo] = '\0';
     602                input[pmatch[9].rm_eo] = '\0';
     603
     604                port = input + pmatch[8].rm_so;
     605                filesize = atoll( input + pmatch[9].rm_so );
    537606
    538607                memset( &hints, 0, sizeof ( struct addrinfo ) );
     
    542611                if ( ( gret = getaddrinfo( host, port, &hints, &rp ) ) )
    543612                {
     613                        g_free( input );
    544614                        imcb_log( ic, "DCC: getaddrinfo() failed with %s "
    545615                                  "when parsing incoming 'DCC SEND': "
     
    555625
    556626                freeaddrinfo( rp );
    557 
    558                 irc->file_transfers = g_slist_prepend( irc->file_transfers, ft );
     627                g_free( input );
     628
     629                df->ic->irc->file_transfers = g_slist_prepend( df->ic->irc->file_transfers, ft );
    559630
    560631                return ft;
    561632        }
    562         else
    563                 imcb_log( ic, "DCC: couldnt parse `DCC SEND' line" );
     633
     634        imcb_log( ic, "DCC: couldnt parse 'DCC SEND' line: %s", line );
    564635
    565636        return NULL;
    566637}
     638
  • dcc.h

    rf1cea66 r560d0a0  
    9595} dcc_file_transfer_t;
    9696
    97 file_transfer_t *dccs_send_start( struct im_connection *ic, irc_user_t *iu, const char *file_name, size_t file_size );
     97file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, char *file_name, size_t file_size );
     98
    9899void dcc_canceled( file_transfer_t *file, char *reason );
     100
    99101gboolean dccs_send_write( file_transfer_t *file, char *data, unsigned int data_size );
    100 file_transfer_t *dcc_request( struct im_connection *ic, char* const* ctcp );
    101 void dcc_finish( file_transfer_t *file );
    102 void dcc_close( file_transfer_t *file );
    103 gboolean dccs_recv_start( file_transfer_t *ft );
    104102
     103file_transfer_t *dcc_request( struct im_connection *ic, char *line );
    105104#endif
  • doc/user-guide/commands.xml

    rf1cea66 r560d0a0  
    593593
    594594        <bitlbee-setting name="handle_unknown" type="string" scope="global">
    595                 <default>add_channel</default>
     595                <default>root</default>
    596596                <possible-values>root, add, add_private, add_channel, ignore</possible-values>
    597597
     
    11141114
    11151115        <bitlbee-command name="identify">
    1116                 <syntax>identify [-noload|-force] &lt;password&gt;</syntax>
     1116                <syntax>identify &lt;password&gt;</syntax>
    11171117                <short-description>Identify yourself with your password</short-description>
    11181118
     
    11241124                        <para>
    11251125                                Once you're registered, you can change your password using <emphasis>set password &lt;password&gt;</emphasis>.
    1126                         </para>
    1127 
    1128                         <para>
    1129                                 The <emphasis>-noload</emphasis> and <emphasis>-force</emphasis> flags can be used to identify when you're logged into some IM accounts already. <emphasis>-force</emphasis> will let you identify yourself and load all saved accounts (and keep the accounts you're logged into already).
    1130                         </para>
    1131                        
    1132                         <para>
    1133                                 <emphasis>-noload</emphasis> will log you in but not load any accounts and settings saved under your current nickname. These will be overwritten once you save your settings (i.e. when you disconnect).
    11341126                        </para>
    11351127                </description>
  • doc/user-guide/misc.xml

    rf1cea66 r560d0a0  
    117117</sect1>
    118118
    119 <sect1 id="nick_changes">
    120 <title>Changing your nickname</title>
    121 
    122 <para>
    123 BitlBee now allows you to change your nickname. So far this was not possible because it made managing saved accounts more complicated.
    124 </para>
    125 
    126 <para>
    127 The restriction no longer exists now though. When you change your nick (just using the <emphasis>/nick</emphasis> command), your logged-in status will be reset, which means any changes made to your settings/accounts will not be saved.
    128 </para>
    129 
    130 <para>
    131 To restore your logged-in status, you need to either use the <emphasis>register</emphasis> command to create an account under the new nickname, or use <emphasis>identify -noload</emphasis> to re-identify yourself under the new nickname. The <emphasis>-noload</emphasis> flag tells the command to verify your password and log you in, but not load any new settings. See <emphasis>help identify</emphasis> for more information.
    132 </para>
    133 
    134 </sect1>
    135 
    136119</chapter>
  • ipc.c

    rf1cea66 r560d0a0  
    138138       
    139139        if( strchr( irc->umode, 'w' ) )
    140                 irc_write( irc, ":%s WALLOPS :%s", irc->root->host, cmd[1] );
     140                irc_write( irc, ":%s WALLOPS :%s", irc->myhost, cmd[1] );
    141141}
    142142
     
    147147       
    148148        if( strchr( irc->umode, 's' ) )
    149                 irc_write( irc, ":%s NOTICE %s :%s", irc->root->host, irc->user->nick, cmd[1] );
     149                irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] );
    150150}
    151151
     
    156156       
    157157        if( strchr( irc->umode, 'o' ) )
    158                 irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->root->host, irc->user->nick, cmd[1] );
     158                irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->myhost, irc->nick, cmd[1] );
    159159}
    160160
     
    176176                return;
    177177       
    178         if( nick_cmp( cmd[1], irc->user->nick ) != 0 )
     178        if( nick_cmp( cmd[1], irc->nick ) != 0 )
    179179                return;         /* It's not for us. */
    180180       
    181         irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->root->nick, irc->root->nick, irc->root->host, irc->user->nick, cmd[2] );
     181        irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->mynick, irc->mynick, irc->myhost, irc->nick, cmd[2] );
    182182        irc_abort( irc, 0, "Killed by operator: %s", cmd[2] );
    183183}
     
    188188                ipc_to_master_str( "HELLO\r\n" );
    189189        else
    190                 ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname );
     190                ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
    191191}
    192192
  • irc.c

    rf1cea66 r560d0a0  
    55  \********************************************************************/
    66
    7 /* The IRC-based UI (for now the only one)                              */
     7/* The big hairy IRCd part of the project                               */
    88
    99/*
     
    2424*/
    2525
     26#define BITLBEE_CORE
    2627#include "bitlbee.h"
     28#include "sock.h"
    2729#include "ipc.h"
    2830#include "dcc.h"
    2931
    30 GSList *irc_connection_list;
    31 
    32 static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond );
    33 static char *set_eval_charset( set_t *set, char *value );
    34 static char *set_eval_password( set_t *set, char *value );
     32static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond );
     33
     34GSList *irc_connection_list = NULL;
     35
     36static char *set_eval_password( set_t *set, char *value )
     37{
     38        irc_t *irc = set->data;
     39       
     40        if( irc->status & USTATUS_IDENTIFIED && value )
     41        {
     42                irc_setpass( irc, value );
     43                return NULL;
     44        }
     45        else
     46        {
     47                return SET_INVALID;
     48        }
     49}
     50
     51static char *set_eval_charset( set_t *set, char *value )
     52{
     53        irc_t *irc = set->data;
     54        char *test;
     55        gsize test_bytes = 0;
     56        GIConv ic, oc;
     57
     58        if( g_strcasecmp( value, "none" ) == 0 )
     59                value = g_strdup( "utf-8" );
     60
     61        if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
     62        {
     63                return NULL;
     64        }
     65       
     66        /* Do a test iconv to see if the user picked an IRC-compatible
     67           charset (for example utf-16 goes *horribly* wrong). */
     68        if( ( test = g_convert_with_iconv( " ", 1, oc, NULL, &test_bytes, NULL ) ) == NULL ||
     69            test_bytes > 1 )
     70        {
     71                g_free( test );
     72                g_iconv_close( oc );
     73                irc_usermsg( irc, "Unsupported character set: The IRC protocol "
     74                                  "only supports 8-bit character sets." );
     75                return NULL;
     76        }
     77        g_free( test );
     78       
     79        if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
     80        {
     81                g_iconv_close( oc );
     82                return NULL;
     83        }
     84       
     85        if( irc->iconv != (GIConv) -1 )
     86                g_iconv_close( irc->iconv );
     87        if( irc->oconv != (GIConv) -1 )
     88                g_iconv_close( irc->oconv );
     89       
     90        irc->iconv = ic;
     91        irc->oconv = oc;
     92
     93        return value;
     94}
     95
     96static char *set_eval_away_status( set_t *set, char *value )
     97{
     98        irc_t *irc = set->data;
     99        account_t *a;
     100       
     101        g_free( set->value );
     102        set->value = g_strdup( value );
     103       
     104        for( a = irc->accounts; a; a = a->next )
     105        {
     106                struct im_connection *ic = a->ic;
     107               
     108                if( ic && ic->flags & OPT_LOGGED_IN )
     109                        imc_away_send_update( ic );
     110        }
     111       
     112        return value;
     113}
    35114
    36115irc_t *irc_new( int fd )
     
    39118        struct sockaddr_storage sock;
    40119        socklen_t socklen = sizeof( sock );
    41         char *host = NULL, *myhost = NULL;
    42         irc_user_t *iu;
    43120        set_t *s;
    44         bee_t *b;
    45121       
    46122        irc = g_new0( irc_t, 1 );
     
    54130        irc->last_pong = gettime();
    55131       
    56         irc->nick_user_hash = g_hash_table_new( g_str_hash, g_str_equal );
     132        irc->userhash = g_hash_table_new( g_str_hash, g_str_equal );
    57133        irc->watches = g_hash_table_new( g_str_hash, g_str_equal );
     134       
     135        strcpy( irc->umode, UMODE );
     136        irc->mynick = g_strdup( ROOT_NICK );
     137        irc->channel = g_strdup( ROOT_CHAN );
    58138       
    59139        irc->iconv = (GIConv) -1;
     
    62142        if( global.conf->hostname )
    63143        {
    64                 myhost = g_strdup( global.conf->hostname );
     144                irc->myhost = g_strdup( global.conf->hostname );
    65145        }
    66146        else if( getsockname( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 )
     
    71151                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
    72152                {
    73                         myhost = g_strdup( ipv6_unwrap( buf ) );
     153                        irc->myhost = g_strdup( ipv6_unwrap( buf ) );
    74154                }
    75155        }
     
    82162                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
    83163                {
    84                         host = g_strdup( ipv6_unwrap( buf ) );
    85                 }
    86         }
    87        
    88         if( host == NULL )
    89                 host = g_strdup( "localhost.localdomain" );
    90         if( myhost == NULL )
    91                 myhost = g_strdup( "localhost.localdomain" );
     164                        irc->host = g_strdup( ipv6_unwrap( buf ) );
     165                }
     166        }
     167       
     168        if( irc->host == NULL )
     169                irc->host = g_strdup( "localhost.localdomain" );
     170        if( irc->myhost == NULL )
     171                irc->myhost = g_strdup( "localhost.localdomain" );
    92172       
    93173        if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 )
    94174                irc->ping_source_id = b_timeout_add( global.conf->ping_interval * 1000, irc_userping, irc );
     175       
     176        irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost, "BitlBee-IRCd initialized, please go on" );
    95177
    96178        irc_connection_list = g_slist_append( irc_connection_list, irc );
    97179       
    98         b = irc->b = bee_new();
    99         b->ui_data = irc;
    100         b->ui = &irc_ui_funcs;
    101        
    102         s = set_add( &b->set, "away_devoice", "true", set_eval_away_devoice, irc );
    103         s = set_add( &b->set, "charset", "utf-8", set_eval_charset, irc );
    104         s = set_add( &b->set, "default_target", "root", NULL, irc );
    105         s = set_add( &b->set, "display_namechanges", "false", set_eval_bool, irc );
    106         s = set_add( &b->set, "display_timestamps", "true", set_eval_bool, irc );
    107         s = set_add( &b->set, "handle_unknown", "add_channel", NULL, irc );
    108         s = set_add( &b->set, "lcnicks", "true", set_eval_bool, irc );
    109         s = set_add( &b->set, "ops", "both", set_eval_irc_channel_ops, irc );
    110         s = set_add( &b->set, "paste_buffer", "false", set_eval_bool, irc );
    111         s->old_key = g_strdup( "buddy_sendbuffer" );
    112         s = set_add( &b->set, "paste_buffer_delay", "200", set_eval_int, irc );
    113         s->old_key = g_strdup( "buddy_sendbuffer_delay" );
    114         s = set_add( &b->set, "password", NULL, set_eval_password, irc );
     180        s = set_add( &irc->set, "away", NULL,  set_eval_away_status, irc );
    115181        s->flags |= SET_NULL_OK;
    116         s = set_add( &b->set, "private", "true", set_eval_bool, irc );
    117         s = set_add( &b->set, "query_order", "lifo", NULL, irc );
    118         s = set_add( &b->set, "root_nick", ROOT_NICK, set_eval_root_nick, irc );
    119         s = set_add( &b->set, "simulate_netsplit", "true", set_eval_bool, irc );
    120         s = set_add( &b->set, "timezone", "local", set_eval_timezone, irc );
    121         s = set_add( &b->set, "to_char", ": ", set_eval_to_char, irc );
    122         s = set_add( &b->set, "typing_notice", "false", set_eval_bool, irc );
    123 
    124         irc->root = iu = irc_user_new( irc, ROOT_NICK );
    125         iu->host = g_strdup( myhost );
    126         iu->fullname = g_strdup( ROOT_FN );
    127         iu->f = &irc_user_root_funcs;
    128        
    129         iu = irc_user_new( irc, NS_NICK );
    130         iu->host = g_strdup( myhost );
    131         iu->fullname = g_strdup( ROOT_FN );
    132         iu->f = &irc_user_root_funcs;
    133        
    134         irc->user = g_new0( irc_user_t, 1 );
    135         irc->user->host = g_strdup( host );
     182        s = set_add( &irc->set, "away_devoice", "true",  set_eval_away_devoice, irc );
     183        s = set_add( &irc->set, "auto_connect", "true", set_eval_bool, irc );
     184        s = set_add( &irc->set, "auto_reconnect", "true", set_eval_bool, irc );
     185        s = set_add( &irc->set, "auto_reconnect_delay", "5*3<900", set_eval_account_reconnect_delay, irc );
     186        s = set_add( &irc->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
     187        s = set_add( &irc->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
     188        s = set_add( &irc->set, "charset", "utf-8", set_eval_charset, irc );
     189        s = set_add( &irc->set, "control_channel", irc->channel, set_eval_control_channel, irc );
     190        s = set_add( &irc->set, "debug", "false", set_eval_bool, irc );
     191        s = set_add( &irc->set, "default_target", "root", NULL, irc );
     192        s = set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc );
     193        s = set_add( &irc->set, "display_timestamps", "true", set_eval_bool, irc );
     194        s = set_add( &irc->set, "handle_unknown", "root", NULL, irc );
     195        s = set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc );
     196        s = set_add( &irc->set, "ops", "both", set_eval_ops, irc );
     197        s = set_add( &irc->set, "password", NULL, set_eval_password, irc );
     198        s->flags |= SET_NULL_OK;
     199        s = set_add( &irc->set, "private", "true", set_eval_bool, irc );
     200        s = set_add( &irc->set, "query_order", "lifo", NULL, irc );
     201        s = set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc );
     202        s = set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
     203        s = set_add( &irc->set, "show_offline", "false", set_eval_bool, irc );
     204        s = set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
     205        s = set_add( &irc->set, "status", NULL,  set_eval_away_status, irc );
     206        s->flags |= SET_NULL_OK;
     207        s = set_add( &irc->set, "strip_html", "true", NULL, irc );
     208        s = set_add( &irc->set, "timezone", "local", set_eval_timezone, irc );
     209        s = set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc );
     210        s = set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc );
    136211       
    137212        conf_loaddefaults( irc );
    138213       
    139214        /* Evaluator sets the iconv/oconv structures. */
    140         set_eval_charset( set_find( &b->set, "charset" ), set_getstr( &b->set, "charset" ) );
    141        
    142         irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, "BitlBee-IRCd initialized, please go on" );
    143        
    144         g_free( myhost );
    145         g_free( host );
     215        set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) );
    146216       
    147217        nogaim_init();
    148218       
    149         return irc;
     219        return( irc );
    150220}
    151221
     
    168238               
    169239                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
    170                                    irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, reason );
     240                                   irc->nick ? irc->nick : "(NONE)", irc->host, reason );
    171241               
    172242                g_free( reason );
     
    178248               
    179249                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
    180                                    irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, "No reason given" );
     250                                   irc->nick ? irc->nick : "(NONE)", irc->host, "No reason given" );
    181251        }
    182252       
     
    199269}
    200270
    201 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data );
    202 
     271static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
     272{
     273        g_free( key );
     274       
     275        return( TRUE );
     276}
     277
     278/* Because we have no garbage collection, this is quite annoying */
    203279void irc_free( irc_t * irc )
    204280{
     281        user_t *user, *usertmp;
     282       
    205283        log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
    206284       
    207         if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) )
     285        if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->set, "save_on_quit" ) )
    208286                if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
    209                         log_message( LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick );
     287                        irc_usermsg( irc, "Error while saving settings!" );
    210288       
    211289        irc_connection_list = g_slist_remove( irc_connection_list, irc );
     290       
     291        while( irc->accounts )
     292        {
     293                if( irc->accounts->ic )
     294                        imc_logout( irc->accounts->ic, FALSE );
     295                else if( irc->accounts->reconnect )
     296                        cancel_auto_reconnect( irc->accounts );
     297               
     298                if( irc->accounts->ic == NULL )
     299                        account_del( irc, irc->accounts );
     300                else
     301                        /* Nasty hack, but account_del() doesn't work in this
     302                           case and we don't want infinite loops, do we? ;-) */
     303                        irc->accounts = irc->accounts->next;
     304        }
    212305       
    213306        while( irc->queries != NULL )
    214307                query_del( irc, irc->queries );
    215308       
    216         /* This is a little bit messy: bee_free() frees all b->users which
    217            calls us back to free the corresponding irc->users. So do this
    218            before we clear the remaining ones ourselves. */
    219         bee_free( irc->b );
    220        
    221         while( irc->users )
    222                 irc_user_free( irc, (irc_user_t *) irc->users->data );
    223        
    224         while( irc->channels )
    225                 irc_channel_free( irc->channels->data );
     309        while( irc->set )
     310                set_del( &irc->set, irc->set->key );
     311       
     312        if (irc->users != NULL)
     313        {
     314                user = irc->users;
     315                while( user != NULL )
     316                {
     317                        g_free( user->nick );
     318                        g_free( user->away );
     319                        g_free( user->handle );
     320                        if( user->user != user->nick ) g_free( user->user );
     321                        if( user->host != user->nick ) g_free( user->host );
     322                        if( user->realname != user->nick ) g_free( user->realname );
     323                        b_event_remove( user->sendbuf_timer );
     324                                       
     325                        usertmp = user;
     326                        user = user->next;
     327                        g_free( usertmp );
     328                }
     329        }
    226330       
    227331        if( irc->ping_source_id > 0 )
     
    235339        irc->fd = -1;
    236340       
    237         g_hash_table_foreach_remove( irc->nick_user_hash, irc_free_hashkey, NULL );
    238         g_hash_table_destroy( irc->nick_user_hash );
     341        g_hash_table_foreach_remove( irc->userhash, irc_free_hashkey, NULL );
     342        g_hash_table_destroy( irc->userhash );
    239343       
    240344        g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL );
     
    248352        g_free( irc->sendbuffer );
    249353        g_free( irc->readbuffer );
     354       
     355        g_free( irc->nick );
     356        g_free( irc->user );
     357        g_free( irc->host );
     358        g_free( irc->realname );
    250359        g_free( irc->password );
    251         g_free( irc->last_root_cmd );
     360       
     361        g_free( irc->myhost );
     362        g_free( irc->mynick );
     363       
     364        g_free( irc->channel );
     365       
     366        g_free( irc->last_target );
    252367       
    253368        g_free( irc );
     
    261376}
    262377
    263 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
    264 {
    265         g_free( key );
    266        
    267         return( TRUE );
    268 }
    269 
    270378/* USE WITH CAUTION!
    271379   Sets pass without checking */
    272 void irc_setpass (irc_t *irc, const char *pass)
     380void irc_setpass (irc_t *irc, const char *pass) 
    273381{
    274382        g_free (irc->password);
     
    281389}
    282390
    283 static char *set_eval_password( set_t *set, char *value )
    284 {
    285         irc_t *irc = set->data;
    286        
    287         if( irc->status & USTATUS_IDENTIFIED && value )
    288         {
    289                 irc_setpass( irc, value );
    290                 return NULL;
    291         }
    292         else
    293         {
    294                 return SET_INVALID;
    295         }
    296 }
    297 
    298 static char **irc_splitlines( char *buffer );
    299 
    300391void irc_process( irc_t *irc )
    301392{
     
    305396        if( irc->readbuffer != NULL )
    306397        {
    307                 lines = irc_splitlines( irc->readbuffer );
     398                lines = irc_tokenize( irc->readbuffer );
    308399               
    309400                for( i = 0; *lines[i] != '\0'; i ++ )
     
    342433                                                                  "`help set charset' for more information. Your "
    343434                                                                  "message was ignored.",
    344                                                                   set_getstr( &irc->b->set, "charset" ) );
     435                                                                  set_getstr( &irc->set, "charset" ) );
    345436                                               
    346437                                                g_free( conv );
     
    349440                                        else
    350441                                        {
    351                                                 irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host,
     442                                                irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost,
    352443                                                           "Warning: invalid characters received at login time." );
    353444                                               
     
    387478}
    388479
    389 /* Splits a long string into separate lines. The array is NULL-terminated
    390    and, unless the string contains an incomplete line at the end, ends with
    391    an empty string. Could use g_strsplit() but this one does it in-place.
    392    (So yes, it's destructive.) */
    393 static char **irc_splitlines( char *buffer )
     480/* Splits a long string into separate lines. The array is NULL-terminated and, unless the string
     481   contains an incomplete line at the end, ends with an empty string. */
     482char **irc_tokenize( char *buffer )
    394483{
    395484        int i, j, n = 3;
     
    522611}
    523612
     613void irc_reply( irc_t *irc, int code, char *format, ... )
     614{
     615        char text[IRC_MAX_LINE];
     616        va_list params;
     617       
     618        va_start( params, format );
     619        g_vsnprintf( text, IRC_MAX_LINE, format, params );
     620        va_end( params );
     621        irc_write( irc, ":%s %03d %s %s", irc->myhost, code, irc->nick?irc->nick:"*", text );
     622       
     623        return;
     624}
     625
     626int irc_usermsg( irc_t *irc, char *format, ... )
     627{
     628        char text[1024];
     629        va_list params;
     630        char is_private = 0;
     631        user_t *u;
     632       
     633        u = user_find( irc, irc->mynick );
     634        is_private = u->is_private;
     635       
     636        va_start( params, format );
     637        g_vsnprintf( text, sizeof( text ), format, params );
     638        va_end( params );
     639       
     640        return( irc_msgfrom( irc, u->nick, text ) );
     641}
     642
    524643void irc_write( irc_t *irc, char *format, ... )
    525644{
     
    532651        return;
    533652}
    534 
    535 void irc_write_all( int now, char *format, ... )
    536 {
    537         va_list params;
    538         GSList *temp;   
    539        
    540         va_start( params, format );
    541        
    542         temp = irc_connection_list;
    543         while( temp != NULL )
    544         {
    545                 irc_t *irc = temp->data;
    546                
    547                 if( now )
    548                 {
    549                         g_free( irc->sendbuffer );
    550                         irc->sendbuffer = g_strdup( "\r\n" );
    551                 }
    552                 irc_vawrite( temp->data, format, params );
    553                 if( now )
    554                 {
    555                         bitlbee_io_current_client_write( irc, irc->fd, B_EV_IO_WRITE );
    556                 }
    557                 temp = temp->next;
    558         }
    559        
    560         va_end( params );
    561         return;
    562 }
    563653
    564654void irc_vawrite( irc_t *irc, char *format, va_list params )
     
    617707}
    618708
     709void irc_write_all( int now, char *format, ... )
     710{
     711        va_list params;
     712        GSList *temp;   
     713       
     714        va_start( params, format );
     715       
     716        temp = irc_connection_list;
     717        while( temp != NULL )
     718        {
     719                irc_t *irc = temp->data;
     720               
     721                if( now )
     722                {
     723                        g_free( irc->sendbuffer );
     724                        irc->sendbuffer = g_strdup( "\r\n" );
     725                }
     726                irc_vawrite( temp->data, format, params );
     727                if( now )
     728                {
     729                        bitlbee_io_current_client_write( irc, irc->fd, B_EV_IO_WRITE );
     730                }
     731                temp = temp->next;
     732        }
     733       
     734        va_end( params );
     735        return;
     736}
     737
     738void irc_names( irc_t *irc, char *channel )
     739{
     740        user_t *u;
     741        char namelist[385] = "";
     742        struct groupchat *c = NULL;
     743        char *ops = set_getstr( &irc->set, "ops" );
     744       
     745        /* RFCs say there is no error reply allowed on NAMES, so when the
     746           channel is invalid, just give an empty reply. */
     747       
     748        if( g_strcasecmp( channel, irc->channel ) == 0 )
     749        {
     750                for( u = irc->users; u; u = u->next ) if( u->online )
     751                {
     752                        if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 )
     753                        {
     754                                irc_reply( irc, 353, "= %s :%s", channel, namelist );
     755                                *namelist = 0;
     756                        }
     757                       
     758                        if( u->ic && !u->away && set_getbool( &irc->set, "away_devoice" ) )
     759                                strcat( namelist, "+" );
     760                        else if( ( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) == 0 ) ) ||
     761                                 ( strcmp( u->nick, irc->nick ) == 0 && ( strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) == 0 ) ) )
     762                                strcat( namelist, "@" );
     763                       
     764                        strcat( namelist, u->nick );
     765                        strcat( namelist, " " );
     766                }
     767        }
     768        else if( ( c = irc_chat_by_channel( irc, channel ) ) )
     769        {
     770                GList *l;
     771               
     772                /* root and the user aren't in the channel userlist but should
     773                   show up in /NAMES, so list them first: */
     774                sprintf( namelist, "%s%s %s%s ", strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->mynick,
     775                                                 strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->nick );
     776               
     777                for( l = c->in_room; l; l = l->next ) if( ( u = user_findhandle( c->ic, l->data ) ) )
     778                {
     779                        if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 )
     780                        {
     781                                irc_reply( irc, 353, "= %s :%s", channel, namelist );
     782                                *namelist = 0;
     783                        }
     784                       
     785                        strcat( namelist, u->nick );
     786                        strcat( namelist, " " );
     787                }
     788        }
     789       
     790        if( *namelist )
     791                irc_reply( irc, 353, "= %s :%s", channel, namelist );
     792       
     793        irc_reply( irc, 366, "%s :End of /NAMES list", channel );
     794}
     795
    619796int irc_check_login( irc_t *irc )
    620797{
    621         if( irc->user->user && irc->user->nick )
     798        if( irc->user && irc->nick )
    622799        {
    623800                if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) )
    624801                {
    625                         irc_send_num( irc, 464, ":This server is password-protected." );
     802                        irc_reply( irc, 464, ":This server is password-protected." );
    626803                        return 0;
    627804                }
    628805                else
    629806                {
    630                         irc_channel_t *ic;
    631                         irc_user_t *iu = irc->user;
    632                        
    633                         irc->user = irc_user_new( irc, iu->nick );
    634                         irc->user->user = iu->user;
    635                         irc->user->host = iu->host;
    636                         irc->user->fullname = iu->fullname;
    637                         irc->user->f = &irc_user_self_funcs;
    638                         g_free( iu->nick );
    639                         g_free( iu );
    640                        
    641                         if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
    642                                 ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname );
    643                        
    644                         irc->status |= USTATUS_LOGGED_IN;
    645                        
    646                         irc_send_login( irc );
    647                        
    648                         irc->umode[0] = '\0';
    649                         irc_umode_set( irc, "+" UMODE, TRUE );
    650                        
    651                         ic = irc->default_channel = irc_channel_new( irc, ROOT_CHAN );
    652                         irc_channel_set_topic( ic, CONTROL_TOPIC, irc->root );
    653                         irc_channel_add_user( ic, irc->user );
    654                        
    655                         irc->last_root_cmd = g_strdup( ROOT_CHAN );
    656                        
    657                         irc_send_msg( irc->root, "PRIVMSG", ROOT_CHAN,
    658                                       "Welcome to the BitlBee gateway!\n\n"
    659                                       "If you've never used BitlBee before, please do read the help "
    660                                       "information using the \x02help\x02 command. Lots of FAQs are "
    661                                       "answered there.\n"
    662                                       "If you already have an account on this server, just use the "
    663                                       "\x02identify\x02 command to identify yourself.", NULL );
    664                        
    665                         /* This is for bug #209 (use PASS to identify to NickServ). */
    666                         if( irc->password != NULL )
    667                         {
    668                                 char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
    669                                
    670                                 irc_setpass( irc, NULL );
    671                                 root_command( irc, send_cmd );
    672                                 g_free( send_cmd[1] );
    673                         }
    674                        
     807                        irc_login( irc );
    675808                        return 1;
    676809                }
     
    683816}
    684817
    685 void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv )
     818void irc_login( irc_t *irc )
     819{
     820        user_t *u;
     821       
     822        irc_reply( irc,   1, ":Welcome to the BitlBee gateway, %s", irc->nick );
     823        irc_reply( irc,   2, ":Host %s is running BitlBee " BITLBEE_VERSION " " ARCH "/" CPU ".", irc->myhost );
     824        irc_reply( irc,   3, ":%s", IRCD_INFO );
     825        irc_reply( irc,   4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES );
     826        irc_reply( irc,   5, "PREFIX=(ov)@+ CHANTYPES=%s CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee "
     827                             "CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server",
     828                             CTYPES, CMODES, MAX_NICK_LENGTH - 1 );
     829        irc_motd( irc );
     830        irc->umode[0] = '\0';
     831        irc_umode_set( irc, "+" UMODE, 1 );
     832
     833        u = user_add( irc, irc->mynick );
     834        u->host = g_strdup( irc->myhost );
     835        u->realname = g_strdup( ROOT_FN );
     836        u->online = 1;
     837        u->send_handler = root_command_string;
     838        u->is_private = 0; /* [SH] The channel is root's personal playground. */
     839        irc_spawn( irc, u );
     840       
     841        u = user_add( irc, NS_NICK );
     842        u->host = g_strdup( irc->myhost );
     843        u->realname = g_strdup( ROOT_FN );
     844        u->online = 0;
     845        u->send_handler = root_command_string;
     846        u->is_private = 1; /* [SH] NickServ is not in the channel, so should always /query. */
     847       
     848        u = user_add( irc, irc->nick );
     849        u->user = g_strdup( irc->user );
     850        u->host = g_strdup( irc->host );
     851        u->realname = g_strdup( irc->realname );
     852        u->online = 1;
     853        irc_spawn( irc, u );
     854       
     855        irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\n"
     856                          "If you've never used BitlBee before, please do read the help "
     857                          "information using the \x02help\x02 command. Lots of FAQs are "
     858                          "answered there.\n"
     859                          "If you already have an account on this server, just use the "
     860                          "\x02identify\x02 command to identify yourself." );
     861       
     862        if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
     863                ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
     864       
     865        irc->status |= USTATUS_LOGGED_IN;
     866       
     867        /* This is for bug #209 (use PASS to identify to NickServ). */
     868        if( irc->password != NULL )
     869        {
     870                char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
     871               
     872                irc_setpass( irc, NULL );
     873                root_command( irc, send_cmd );
     874                g_free( send_cmd[1] );
     875        }
     876}
     877
     878void irc_motd( irc_t *irc )
     879{
     880        int fd;
     881       
     882        fd = open( global.conf->motdfile, O_RDONLY );
     883        if( fd == -1 )
     884        {
     885                irc_reply( irc, 422, ":We don't need MOTDs." );
     886        }
     887        else
     888        {
     889                char linebuf[80];       /* Max. line length for MOTD's is 79 chars. It's what most IRC networks seem to do. */
     890                char *add, max;
     891                int len;
     892               
     893                linebuf[79] = len = 0;
     894                max = sizeof( linebuf ) - 1;
     895               
     896                irc_reply( irc, 375, ":- %s Message Of The Day - ", irc->myhost );
     897                while( read( fd, linebuf + len, 1 ) == 1 )
     898                {
     899                        if( linebuf[len] == '\n' || len == max )
     900                        {
     901                                linebuf[len] = 0;
     902                                irc_reply( irc, 372, ":- %s", linebuf );
     903                                len = 0;
     904                        }
     905                        else if( linebuf[len] == '%' )
     906                        {
     907                                read( fd, linebuf + len, 1 );
     908                                if( linebuf[len] == 'h' )
     909                                        add = irc->myhost;
     910                                else if( linebuf[len] == 'v' )
     911                                        add = BITLBEE_VERSION;
     912                                else if( linebuf[len] == 'n' )
     913                                        add = irc->nick;
     914                                else
     915                                        add = "%";
     916                               
     917                                strncpy( linebuf + len, add, max - len );
     918                                while( linebuf[++len] );
     919                        }
     920                        else if( len < max )
     921                        {
     922                                len ++;
     923                        }
     924                }
     925                irc_reply( irc, 376, ":End of MOTD" );
     926                close( fd );
     927        }
     928}
     929
     930void irc_topic( irc_t *irc, char *channel )
     931{
     932        struct groupchat *c = irc_chat_by_channel( irc, channel );
     933       
     934        if( c && c->topic )
     935                irc_reply( irc, 332, "%s :%s", channel, c->topic );
     936        else if( g_strcasecmp( channel, irc->channel ) == 0 )
     937                irc_reply( irc, 332, "%s :%s", channel, CONTROL_TOPIC );
     938        else
     939                irc_reply( irc, 331, "%s :No topic for this channel", channel );
     940}
     941
     942void irc_umode_set( irc_t *irc, char *s, int allow_priv )
    686943{
    687944        /* allow_priv: Set to 0 if s contains user input, 1 if you want
    688945           to set a "privileged" mode (+o, +R, etc). */
    689         char m[128], st = 1;
    690         const char *t;
     946        char m[256], st = 1, *t;
    691947        int i;
    692948        char changes[512], *p, st2 = 2;
     
    696952       
    697953        for( t = irc->umode; *t; t ++ )
    698                 if( *t < sizeof( m ) )
    699                         m[(int)*t] = 1;
    700        
     954                m[(int)*t] = 1;
     955
    701956        p = changes;
    702957        for( t = s; *t; t ++ )
     
    704959                if( *t == '+' || *t == '-' )
    705960                        st = *t == '+';
    706                 else if( ( st == 0 && ( !strchr( UMODES_KEEP, *t ) || allow_priv ) ) ||
    707                          ( st == 1 && strchr( UMODES, *t ) ) ||
    708                          ( st == 1 && allow_priv && strchr( UMODES_PRIV, *t ) ) )
     961                else if( st == 0 || ( strchr( UMODES, *t ) || ( allow_priv && strchr( UMODES_PRIV, *t ) ) ) )
    709962                {
    710963                        if( m[(int)*t] != st)
     
    723976        memset( irc->umode, 0, sizeof( irc->umode ) );
    724977       
    725         for( i = 'A'; i <= 'z' && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
     978        for( i = 0; i < 256 && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
    726979                if( m[i] )
    727980                        irc->umode[strlen(irc->umode)] = i;
    728981       
    729982        if( badflag )
    730                 irc_send_num( irc, 501, ":Unknown MODE flag" );
     983                irc_reply( irc, 501, ":Unknown MODE flag" );
     984        /* Deliberately no !user@host on the prefix here */
    731985        if( *changes )
    732                 irc_write( irc, ":%s!%s@%s MODE %s :%s", irc->user->nick,
    733                            irc->user->user, irc->user->host, irc->user->nick,
    734                            changes );
     986                irc_write( irc, ":%s MODE %s %s", irc->nick, irc->nick, changes );
     987}
     988
     989void irc_spawn( irc_t *irc, user_t *u )
     990{
     991        irc_join( irc, u, irc->channel );
     992}
     993
     994void irc_join( irc_t *irc, user_t *u, char *channel )
     995{
     996        char *nick;
     997       
     998        if( ( g_strcasecmp( channel, irc->channel ) != 0 ) || user_find( irc, irc->nick ) )
     999                irc_write( irc, ":%s!%s@%s JOIN :%s", u->nick, u->user, u->host, channel );
     1000       
     1001        if( nick_cmp( u->nick, irc->nick ) == 0 )
     1002        {
     1003                irc_write( irc, ":%s MODE %s +%s", irc->myhost, channel, CMODE );
     1004                irc_names( irc, channel );
     1005                irc_topic( irc, channel );
     1006        }
     1007       
     1008        nick = g_strdup( u->nick );
     1009        nick_lc( nick );
     1010        if( g_hash_table_lookup( irc->watches, nick ) )
     1011        {
     1012                irc_reply( irc, 600, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged online" );
     1013        }
     1014        g_free( nick );
     1015}
     1016
     1017void irc_part( irc_t *irc, user_t *u, char *channel )
     1018{
     1019        irc_write( irc, ":%s!%s@%s PART %s :%s", u->nick, u->user, u->host, channel, "" );
     1020}
     1021
     1022void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker )
     1023{
     1024        irc_write( irc, ":%s!%s@%s KICK %s %s :%s", kicker->nick, kicker->user, kicker->host, channel, u->nick, "" );
     1025}
     1026
     1027void irc_kill( irc_t *irc, user_t *u )
     1028{
     1029        char *nick, *s;
     1030        char reason[128];
     1031       
     1032        if( u->ic && u->ic->flags & OPT_LOGGING_OUT && set_getbool( &irc->set, "simulate_netsplit" ) )
     1033        {
     1034                if( u->ic->acc->server )
     1035                        g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost,
     1036                                    u->ic->acc->server );
     1037                else if( ( s = strchr( u->ic->acc->user, '@' ) ) )
     1038                        g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost,
     1039                                    s + 1 );
     1040                else
     1041                        g_snprintf( reason, sizeof( reason ), "%s %s.%s", irc->myhost,
     1042                                    u->ic->acc->prpl->name, irc->myhost );
     1043               
     1044                /* proto_opt might contain garbage after the : */
     1045                if( ( s = strchr( reason, ':' ) ) )
     1046                        *s = 0;
     1047        }
     1048        else
     1049        {
     1050                strcpy( reason, "Leaving..." );
     1051        }
     1052       
     1053        irc_write( irc, ":%s!%s@%s QUIT :%s", u->nick, u->user, u->host, reason );
     1054       
     1055        nick = g_strdup( u->nick );
     1056        nick_lc( nick );
     1057        if( g_hash_table_lookup( irc->watches, nick ) )
     1058        {
     1059                irc_reply( irc, 601, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged offline" );
     1060        }
     1061        g_free( nick );
     1062}
     1063
     1064int irc_send( irc_t *irc, char *nick, char *s, int flags )
     1065{
     1066        struct groupchat *c = NULL;
     1067        user_t *u = NULL;
     1068       
     1069        if( strchr( CTYPES, *nick ) )
     1070        {
     1071                if( !( c = irc_chat_by_channel( irc, nick ) ) )
     1072                {
     1073                        irc_reply( irc, 403, "%s :Channel does not exist", nick );
     1074                        return( 0 );
     1075                }
     1076        }
     1077        else
     1078        {
     1079                u = user_find( irc, nick );
     1080               
     1081                if( !u )
     1082                {
     1083                        if( irc->is_private )
     1084                                irc_reply( irc, 401, "%s :Nick does not exist", nick );
     1085                        else
     1086                                irc_usermsg( irc, "Nick `%s' does not exist!", nick );
     1087                        return( 0 );
     1088                }
     1089        }
     1090       
     1091        if( *s == 1 && s[strlen(s)-1] == 1 )
     1092        {
     1093                if( g_strncasecmp( s + 1, "ACTION", 6 ) == 0 )
     1094                {
     1095                        if( s[7] == ' ' ) s ++;
     1096                        s += 3;
     1097                        *(s++) = '/';
     1098                        *(s++) = 'm';
     1099                        *(s++) = 'e';
     1100                        *(s++) = ' ';
     1101                        s -= 4;
     1102                        s[strlen(s)-1] = 0;
     1103                }
     1104                else if( g_strncasecmp( s + 1, "VERSION", 7 ) == 0 )
     1105                {
     1106                        u = user_find( irc, irc->mynick );
     1107                        irc_privmsg( irc, u, "NOTICE", irc->nick, "", "\001VERSION BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\001" );
     1108                        return( 1 );
     1109                }
     1110                else if( g_strncasecmp( s + 1, "PING", 4 ) == 0 )
     1111                {
     1112                        u = user_find( irc, irc->mynick );
     1113                        irc_privmsg( irc, u, "NOTICE", irc->nick, "", s );
     1114                        return( 1 );
     1115                }
     1116                else if( g_strncasecmp( s + 1, "TYPING", 6 ) == 0 )
     1117                {
     1118                        if( u && u->ic && u->ic->acc->prpl->send_typing && strlen( s ) >= 10 )
     1119                        {
     1120                                time_t current_typing_notice = time( NULL );
     1121                               
     1122                                if( current_typing_notice - u->last_typing_notice >= 5 )
     1123                                {
     1124                                        u->ic->acc->prpl->send_typing( u->ic, u->handle, ( s[8] - '0' ) << 8 );
     1125                                        u->last_typing_notice = current_typing_notice;
     1126                                }
     1127                        }
     1128                        return( 1 );
     1129                }
     1130                else if( g_strncasecmp( s + 1, "DCC", 3 ) == 0 )
     1131                {
     1132                        if( u && u->ic && u->ic->acc->prpl->transfer_request )
     1133                        {
     1134                                file_transfer_t *ft = dcc_request( u->ic, s + 5 );
     1135                                if ( ft )
     1136                                        u->ic->acc->prpl->transfer_request( u->ic, ft, u->handle );
     1137                        }
     1138                        return( 1 );
     1139                }               
     1140                else
     1141                {
     1142                        irc_usermsg( irc, "Supported CTCPs are ACTION, VERSION, PING, TYPING, DCC" );
     1143                        return( 0 );
     1144                }
     1145        }
     1146       
     1147        if( u )
     1148        {
     1149                /* For the next message, we probably do have to send new notices... */
     1150                u->last_typing_notice = 0;
     1151                u->is_private = irc->is_private;
     1152               
     1153                if( u->is_private )
     1154                {
     1155                        if( !u->online )
     1156                                irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
     1157                        else if( u->away )
     1158                                irc_reply( irc, 301, "%s :%s", u->nick, u->away );
     1159                }
     1160               
     1161                if( u->send_handler )
     1162                {
     1163                        u->send_handler( irc, u, s, flags );
     1164                        return 1;
     1165                }
     1166        }
     1167        else if( c && c->ic && c->ic->acc && c->ic->acc->prpl )
     1168        {
     1169                return( imc_chat_msg( c, s, 0 ) );
     1170        }
     1171       
     1172        return( 0 );
     1173}
     1174
     1175static gboolean buddy_send_handler_delayed( gpointer data, gint fd, b_input_condition cond )
     1176{
     1177        user_t *u = data;
     1178       
     1179        /* Shouldn't happen, but just to be sure. */
     1180        if( u->sendbuf_len < 2 )
     1181                return FALSE;
     1182       
     1183        u->sendbuf[u->sendbuf_len-2] = 0; /* Cut off the last newline */
     1184        imc_buddy_msg( u->ic, u->handle, u->sendbuf, u->sendbuf_flags );
     1185       
     1186        g_free( u->sendbuf );
     1187        u->sendbuf = NULL;
     1188        u->sendbuf_len = 0;
     1189        u->sendbuf_timer = 0;
     1190        u->sendbuf_flags = 0;
     1191       
     1192        return FALSE;
     1193}
     1194
     1195void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )
     1196{
     1197        if( !u || !u->ic ) return;
     1198       
     1199        if( set_getbool( &irc->set, "buddy_sendbuffer" ) && set_getint( &irc->set, "buddy_sendbuffer_delay" ) > 0 )
     1200        {
     1201                int delay;
     1202               
     1203                if( u->sendbuf_len > 0 && u->sendbuf_flags != flags)
     1204                {
     1205                        /* Flush the buffer */
     1206                        b_event_remove( u->sendbuf_timer );
     1207                        buddy_send_handler_delayed( u, -1, 0 );
     1208                }
     1209
     1210                if( u->sendbuf_len == 0 )
     1211                {
     1212                        u->sendbuf_len = strlen( msg ) + 2;
     1213                        u->sendbuf = g_new( char, u->sendbuf_len );
     1214                        u->sendbuf[0] = 0;
     1215                        u->sendbuf_flags = flags;
     1216                }
     1217                else
     1218                {
     1219                        u->sendbuf_len += strlen( msg ) + 1;
     1220                        u->sendbuf = g_renew( char, u->sendbuf, u->sendbuf_len );
     1221                }
     1222               
     1223                strcat( u->sendbuf, msg );
     1224                strcat( u->sendbuf, "\n" );
     1225               
     1226                delay = set_getint( &irc->set, "buddy_sendbuffer_delay" );
     1227                if( delay <= 5 )
     1228                        delay *= 1000;
     1229               
     1230                if( u->sendbuf_timer > 0 )
     1231                        b_event_remove( u->sendbuf_timer );
     1232                u->sendbuf_timer = b_timeout_add( delay, buddy_send_handler_delayed, u );
     1233        }
     1234        else
     1235        {
     1236                imc_buddy_msg( u->ic, u->handle, msg, flags );
     1237        }
     1238}
     1239
     1240int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg )
     1241{
     1242        char last = 0;
     1243        char *s = msg, *line = msg;
     1244       
     1245        /* The almighty linesplitter .. woohoo!! */
     1246        while( !last )
     1247        {
     1248                if( *s == '\r' && *(s+1) == '\n' )
     1249                        *(s++) = 0;
     1250                if( *s == '\n' )
     1251                {
     1252                        last = s[1] == 0;
     1253                        *s = 0;
     1254                }
     1255                else
     1256                {
     1257                        last = s[0] == 0;
     1258                }
     1259                if( *s == 0 )
     1260                {
     1261                        if( g_strncasecmp( line, "/me ", 4 ) == 0 && ( !prefix || !*prefix ) && g_strcasecmp( type, "PRIVMSG" ) == 0 )
     1262                        {
     1263                                irc_write( irc, ":%s!%s@%s %s %s :\001ACTION %s\001", u->nick, u->user, u->host,
     1264                                           type, to, line + 4 );
     1265                        }
     1266                        else
     1267                        {
     1268                                irc_write( irc, ":%s!%s@%s %s %s :%s%s", u->nick, u->user, u->host,
     1269                                           type, to, prefix ? prefix : "", line );
     1270                        }
     1271                        line = s + 1;
     1272                }
     1273                s ++;
     1274        }
     1275       
     1276        return( 1 );
     1277}
     1278
     1279int irc_msgfrom( irc_t *irc, char *nick, char *msg )
     1280{
     1281        user_t *u = user_find( irc, nick );
     1282        static char *prefix = NULL;
     1283       
     1284        if( !u ) return( 0 );
     1285        if( prefix && *prefix ) g_free( prefix );
     1286       
     1287        if( !u->is_private && nick_cmp( u->nick, irc->mynick ) != 0 )
     1288        {
     1289                int len = strlen( irc->nick) + 3;
     1290                prefix = g_new (char, len );
     1291                g_snprintf( prefix, len, "%s%s", irc->nick, set_getstr( &irc->set, "to_char" ) );
     1292                prefix[len-1] = 0;
     1293        }
     1294        else
     1295        {
     1296                prefix = "";
     1297        }
     1298       
     1299        return( irc_privmsg( irc, u, "PRIVMSG", u->is_private ? irc->nick : irc->channel, prefix, msg ) );
     1300}
     1301
     1302int irc_noticefrom( irc_t *irc, char *nick, char *msg )
     1303{
     1304        user_t *u = user_find( irc, nick );
     1305       
     1306        if( u )
     1307                return( irc_privmsg( irc, u, "NOTICE", irc->nick, "", msg ) );
     1308        else
     1309                return( 0 );
    7351310}
    7361311
     
    7711346}
    7721347
    773 static char *set_eval_charset( set_t *set, char *value )
    774 {
    775         irc_t *irc = (irc_t*) set->data;
    776         char *test;
    777         gsize test_bytes = 0;
    778         GIConv ic, oc;
    779 
    780         if( g_strcasecmp( value, "none" ) == 0 )
    781                 value = g_strdup( "utf-8" );
    782 
    783         if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
    784         {
    785                 return NULL;
    786         }
    787        
    788         /* Do a test iconv to see if the user picked an IRC-compatible
    789            charset (for example utf-16 goes *horribly* wrong). */
    790         if( ( test = g_convert_with_iconv( " ", 1, oc, NULL, &test_bytes, NULL ) ) == NULL ||
    791             test_bytes > 1 )
    792         {
    793                 g_free( test );
    794                 g_iconv_close( oc );
    795                 irc_usermsg( irc, "Unsupported character set: The IRC protocol "
    796                                   "only supports 8-bit character sets." );
    797                 return NULL;
    798         }
    799         g_free( test );
    800        
    801         if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
    802         {
    803                 g_iconv_close( oc );
    804                 return NULL;
    805         }
    806        
    807         if( irc->iconv != (GIConv) -1 )
    808                 g_iconv_close( irc->iconv );
    809         if( irc->oconv != (GIConv) -1 )
    810                 g_iconv_close( irc->oconv );
    811        
    812         irc->iconv = ic;
    813         irc->oconv = oc;
    814 
    815         return value;
    816 }
    817 
    818 char *set_eval_away_devoice( set_t *set, char *value )
    819 {
    820         irc_t *irc = set->data;
    821        
    822         if( !is_bool( value ) )
    823                 return SET_INVALID;
    824        
    825         /* The usual problem: The setting isn't actually changed at this
    826            point and we need it to be, so do it by hand. */
    827         g_free( set->value );
    828         set->value = g_strdup( value );
    829        
    830         bee_irc_channel_update( irc, NULL, NULL );
    831        
    832         return value;
    833 }
     1348struct groupchat *irc_chat_by_channel( irc_t *irc, char *channel )
     1349{
     1350        struct groupchat *c;
     1351        account_t *a;
     1352       
     1353        /* This finds the connection which has a conversation which belongs to this channel */
     1354        for( a = irc->accounts; a; a = a->next )
     1355        {
     1356                if( a->ic == NULL )
     1357                        continue;
     1358               
     1359                c = a->ic->groupchats;
     1360                while( c )
     1361                {
     1362                        if( c->channel && g_strcasecmp( c->channel, channel ) == 0 )
     1363                                return c;
     1364                       
     1365                        c = c->next;
     1366                }
     1367        }
     1368       
     1369        return NULL;
     1370}
  • irc.h

    rf1cea66 r560d0a0  
    55  \********************************************************************/
    66
    7 /* The IRC-based UI (for now the only one)                              */
     7/* The big hairy IRCd part of the project                               */
    88
    99/*
     
    3333#define IRC_PING_STRING "PinglBee"
    3434
    35 #define UMODES "abisw"     /* Allowed umodes (although they mostly do nothing) */
    36 #define UMODES_PRIV "Ro"   /* Allowed, but not by user directly */
    37 #define UMODES_KEEP "R"    /* Don't allow unsetting using /MODE */
    38 #define CMODES "nt"        /* Allowed modes */
    39 #define CMODE "t"          /* Default mode */
    40 #define UMODE "s"          /* Default mode */
    41 
    42 #define CTYPES "&#"        /* Valid channel name prefixes */
     35#define UMODES "abisw"
     36#define UMODES_PRIV "Ro"
     37#define CMODES "nt"
     38#define CMODE "t"
     39#define UMODE "s"
     40#define CTYPES "&#"
    4341
    4442typedef enum
     
    5048        USTATUS_SHUTDOWN = 8
    5149} irc_status_t;
    52 
    53 struct irc_user;
    5450
    5551typedef struct irc
     
    6359        GIConv iconv, oconv;
    6460
    65         struct irc_user *root;
    66         struct irc_user *user;
    67        
    68         char *last_root_cmd;
     61        int sentbytes;
     62        time_t oldtime;
    6963
     64        char *nick;
     65        char *user;
     66        char *host;
     67        char *realname;
    7068        char *password; /* HACK: Used to save the user's password, but before
    7169                           logging in, this may contain a password we should
     
    7472        char umode[8];
    7573       
     74        char *myhost;
     75        char *mynick;
     76
     77        char *channel;
     78        int c_id;
     79
     80        char is_private;                /* Not too nice... */
     81        char *last_target;
     82       
    7683        struct query *queries;
     84        struct account *accounts;
    7785        GSList *file_transfers;
     86        struct chat *chatrooms;
    7887       
    79         GSList *users, *channels;
    80         struct irc_channel *default_channel;
    81         GHashTable *nick_user_hash;
     88        struct __USER *users;
     89        GHashTable *userhash;
    8290        GHashTable *watches;
     91        struct __NICK *nicks;
     92        struct set *set;
    8393
    8494        gint r_watch_source_id;
    8595        gint w_watch_source_id;
    8696        gint ping_source_id;
    87        
    88         struct bee *b;
    8997} irc_t;
    9098
    91 typedef enum
    92 {
    93         IRC_USER_PRIVATE = 1,
    94         IRC_USER_AWAY = 2,
    95 } irc_user_flags_t;
     99#include "user.h"
    96100
    97 typedef struct irc_user
    98 {
    99         irc_t *irc;
    100        
    101         char *nick;
    102         char *user;
    103         char *host;
    104         char *fullname;
    105        
    106         /* Nickname in lowercase for case sensitive searches */
    107         char *key;
    108        
    109         irc_user_flags_t flags;
    110        
    111         GString *pastebuf;
    112         guint pastebuf_timer;
    113        
    114         struct bee_user *bu;
    115        
    116         const struct irc_user_funcs *f;
    117 } irc_user_t;
    118 
    119 struct irc_user_funcs
    120 {
    121         gboolean (*privmsg)( irc_user_t *iu, const char *msg );
    122         gboolean (*ctcp)( irc_user_t *iu, char * const* ctcp );
    123 };
    124 
    125 extern const struct irc_user_funcs irc_user_root_funcs;
    126 extern const struct irc_user_funcs irc_user_self_funcs;
    127 
    128 typedef enum
    129 {
    130         IRC_CHANNEL_JOINED = 1,
    131        
    132         /* Hack: Set this flag right before jumping into IM when we expect
    133            a call to imcb_chat_new(). */
    134         IRC_CHANNEL_CHAT_PICKME = 0x10000,
    135 } irc_channel_flags_t;
    136 
    137 typedef struct irc_channel
    138 {
    139         irc_t *irc;
    140         char *name;
    141         char mode[8];
    142         int flags;
    143        
    144         char *topic;
    145         char *topic_who;
    146         time_t topic_time;
    147        
    148         GSList *users;
    149         struct set *set;
    150        
    151         GString *pastebuf;
    152         guint pastebuf_timer;
    153        
    154         const struct irc_channel_funcs *f;
    155         void *data;
    156 } irc_channel_t;
    157 
    158 struct irc_channel_funcs
    159 {
    160         gboolean (*privmsg)( irc_channel_t *ic, const char *msg );
    161         gboolean (*join)( irc_channel_t *ic );
    162         gboolean (*part)( irc_channel_t *ic, const char *msg );
    163         gboolean (*topic)( irc_channel_t *ic, const char *new );
    164         gboolean (*invite)( irc_channel_t *ic, irc_user_t *iu );
    165        
    166         gboolean (*_init)( irc_channel_t *ic );
    167         gboolean (*_free)( irc_channel_t *ic );
    168 };
    169 
    170 typedef enum
    171 {
    172         IRC_CHANNEL_USER_OP = 1,
    173         IRC_CHANNEL_USER_HALFOP = 2,
    174         IRC_CHANNEL_USER_VOICE = 4,
    175 } irc_channel_user_flags_t;
    176 
    177 typedef struct irc_channel_user
    178 {
    179         irc_user_t *iu;
    180         int flags;
    181 } irc_channel_user_t;
    182 
    183 typedef enum
    184 {
    185         IRC_CC_TYPE_DEFAULT,
    186         IRC_CC_TYPE_REST,
    187         IRC_CC_TYPE_GROUP,
    188         IRC_CC_TYPE_ACCOUNT,
    189 } irc_control_channel_type_t;
    190 
    191 struct irc_control_channel
    192 {
    193         irc_control_channel_type_t type;
    194         struct bee_group *group;
    195         struct account *account;
    196 };
    197 
    198 extern const struct bee_ui_funcs irc_ui_funcs;
    199 
    200 /* irc.c */
    201101extern GSList *irc_connection_list;
    202102
     
    204104void irc_abort( irc_t *irc, int immed, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
    205105void irc_free( irc_t *irc );
    206 void irc_setpass (irc_t *irc, const char *pass);
    207106
     107void irc_exec( irc_t *irc, char **cmd );
    208108void irc_process( irc_t *irc );
    209109char **irc_parse_line( char *line );
    210110char *irc_build_line( char **cmd );
    211111
     112void irc_vawrite( irc_t *irc, char *format, va_list params );
    212113void irc_write( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
    213114void irc_write_all( int now, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
    214 void irc_vawrite( irc_t *irc, char *format, va_list params );
     115void irc_reply( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
     116G_MODULE_EXPORT int irc_usermsg( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
     117char **irc_tokenize( char *buffer );
    215118
     119void irc_login( irc_t *irc );
    216120int irc_check_login( irc_t *irc );
     121void irc_motd( irc_t *irc );
     122void irc_names( irc_t *irc, char *channel );
     123void irc_topic( irc_t *irc, char *channel );
     124void irc_umode_set( irc_t *irc, char *s, int allow_priv );
     125void irc_who( irc_t *irc, char *channel );
     126void irc_spawn( irc_t *irc, user_t *u );
     127void irc_join( irc_t *irc, user_t *u, char *channel );
     128void irc_part( irc_t *irc, user_t *u, char *channel );
     129void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker );
     130void irc_kill( irc_t *irc, user_t *u );
     131void irc_invite( irc_t *irc, char *nick, char *channel );
     132void irc_whois( irc_t *irc, char *nick );
     133void irc_setpass( irc_t *irc, const char *pass ); /* USE WITH CAUTION! */
    217134
    218 void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv );
     135int irc_send( irc_t *irc, char *nick, char *s, int flags );
     136int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg );
     137int irc_msgfrom( irc_t *irc, char *nick, char *msg );
     138int irc_noticefrom( irc_t *irc, char *nick, char *msg );
    219139
    220 /* irc_channel.c */
    221 irc_channel_t *irc_channel_new( irc_t *irc, const char *name );
    222 irc_channel_t *irc_channel_by_name( irc_t *irc, const char *name );
    223 irc_channel_t *irc_channel_get( irc_t *irc, char *id );
    224 int irc_channel_free( irc_channel_t *ic );
    225 int irc_channel_add_user( irc_channel_t *ic, irc_user_t *iu );
    226 int irc_channel_del_user( irc_channel_t *ic, irc_user_t *iu, gboolean silent, const char *msg );
    227 irc_channel_user_t *irc_channel_has_user( irc_channel_t *ic, irc_user_t *iu );
    228 int irc_channel_set_topic( irc_channel_t *ic, const char *topic, const irc_user_t *who );
    229 void irc_channel_user_set_mode( irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags );
    230 void irc_channel_printf( irc_channel_t *ic, char *format, ... );
    231 gboolean irc_channel_name_ok( const char *name );
    232 void irc_channel_update_ops( irc_channel_t *ic, char *value );
    233 char *set_eval_irc_channel_ops( struct set *set, char *value );
    234 
    235 /* irc_commands.c */
    236 void irc_exec( irc_t *irc, char **cmd );
    237 
    238 /* irc_send.c */
    239 void irc_send_num( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
    240 void irc_send_login( irc_t *irc );
    241 void irc_send_motd( irc_t *irc );
    242 void irc_usermsg( irc_t *irc, char *format, ... );
    243 void irc_send_join( irc_channel_t *ic, irc_user_t *iu );
    244 void irc_send_part( irc_channel_t *ic, irc_user_t *iu, const char *reason );
    245 void irc_send_quit( irc_user_t *iu, const char *reason );
    246 void irc_send_names( irc_channel_t *ic );
    247 void irc_send_topic( irc_channel_t *ic, gboolean topic_change );
    248 void irc_send_whois( irc_user_t *iu );
    249 void irc_send_who( irc_t *irc, GSList *l, const char *channel );
    250 void irc_send_msg( irc_user_t *iu, const char *type, const char *dst, const char *msg, const char *prefix );
    251 void irc_send_msg_raw( irc_user_t *iu, const char *type, const char *dst, const char *msg );
    252 void irc_send_msg_f( irc_user_t *iu, const char *type, const char *dst, const char *format, ... ) G_GNUC_PRINTF( 4, 5 );
    253 void irc_send_nick( irc_user_t *iu, const char *new );
    254 void irc_send_channel_user_mode_diff( irc_channel_t *ic, irc_user_t *iu,
    255                                       irc_channel_user_flags_t old, irc_channel_user_flags_t new );
    256 
    257 /* irc_user.c */
    258 irc_user_t *irc_user_new( irc_t *irc, const char *nick );
    259 int irc_user_free( irc_t *irc, irc_user_t *iu );
    260 irc_user_t *irc_user_by_name( irc_t *irc, const char *nick );
    261 int irc_user_set_nick( irc_user_t *iu, const char *new );
    262 gint irc_user_cmp( gconstpointer a_, gconstpointer b_ );
    263 const char *irc_user_get_away( irc_user_t *iu );
    264 
    265 /* irc_util.c */
    266 char *set_eval_timezone( struct set *set, char *value );
    267 char *irc_format_timestamp( irc_t *irc, time_t msg_ts );
    268 
    269 /* irc_im.c */
    270 void bee_irc_channel_update( irc_t *irc, irc_channel_t *ic, irc_user_t *iu );
     140void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags );
     141struct groupchat *irc_chat_by_channel( irc_t *irc, char *channel );
    271142
    272143#endif
  • irc_commands.c

    rf1cea66 r560d0a0  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2010 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2006 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    5353        else if( global.conf->auth_pass )
    5454        {
    55                 irc_send_num( irc, 464, ":Incorrect password" );
     55                irc_reply( irc, 464, ":Incorrect password" );
    5656        }
    5757        else
     
    6565static void irc_cmd_user( irc_t *irc, char **cmd )
    6666{
    67         irc->user->user = g_strdup( cmd[1] );
    68         irc->user->fullname = g_strdup( cmd[4] );
     67        irc->user = g_strdup( cmd[1] );
     68        irc->realname = g_strdup( cmd[4] );
    6969       
    7070        irc_check_login( irc );
     
    7373static void irc_cmd_nick( irc_t *irc, char **cmd )
    7474{
    75         if( irc_user_by_name( irc, cmd[1] ) )
    76         {
    77                 irc_send_num( irc, 433, ":This nick is already in use" );
     75        if( irc->status & USTATUS_IDENTIFIED && irc->nick )
     76        {
     77                irc_reply( irc, 438, "%s %s :You can only change your nick if you're not "
     78                           "logged in (i.e. pre-identify)", irc->nick, cmd[1] );
     79        }
     80        /* This is not clean, but for now it'll have to be like this... */
     81        else if( ( nick_cmp( cmd[1], irc->mynick ) == 0 ) || ( nick_cmp( cmd[1], NS_NICK ) == 0 ) || ( user_find( irc, cmd[1] ) != NULL ) )
     82        {
     83                irc_reply( irc, 433, "%s :This nick is already in use", cmd[1] );
    7884        }
    7985        else if( !nick_ok( cmd[1] ) )
    8086        {
    8187                /* [SH] Invalid characters. */
    82                 irc_send_num( irc, 432, ":This nick contains invalid characters" );
    83         }
    84         else if( irc->user->nick )
    85         {
    86                 if( irc->status & USTATUS_IDENTIFIED )
    87                 {
    88                         irc_setpass( irc, NULL );
    89                         irc->status &= ~USTATUS_IDENTIFIED;
    90                         irc_umode_set( irc, "-R", 1 );
    91                         irc_usermsg( irc, "Changing nicks resets your identify status. "
    92                                      "Re-identify or register a new account if you want "
    93                                      "your configuration to be saved. See \x02help "
    94                                      "nick_changes\x02." );
    95                 }
    96                
    97                 irc_user_set_nick( irc->user, cmd[1] );
    98         }
    99         else
    100         {
    101                 irc->user->nick = g_strdup( cmd[1] );
     88                irc_reply( irc, 432, "%s :This nick contains invalid characters", cmd[1] );
     89        }
     90        else if(irc->nick)
     91        {
     92                if( user_find( irc, irc->nick ) )
     93                        user_rename(irc, irc->nick, cmd[1]);
     94
     95                irc_write( irc, ":%s!%s@%s NICK %s", irc->nick, irc->user, irc->host, cmd[1] );
     96                g_free(irc->nick);
     97                irc->nick = g_strdup( cmd[1] );
     98        }
     99        else
     100        {
     101                irc->nick = g_strdup( cmd[1] );
    102102               
    103103                irc_check_login( irc );
     
    115115static void irc_cmd_ping( irc_t *irc, char **cmd )
    116116{
    117         irc_write( irc, ":%s PONG %s :%s", irc->root->host,
    118                    irc->root->host, cmd[1]?cmd[1]:irc->root->host );
    119 }
    120 
    121 static void irc_cmd_pong( irc_t *irc, char **cmd )
    122 {
    123         /* We could check the value we get back from the user, but in
    124            fact we don't care, we're just happy s/he's still alive. */
    125         irc->last_pong = gettime();
    126         irc->pinging = 0;
    127 }
    128 
    129 static void irc_cmd_join( irc_t *irc, char **cmd )
    130 {
    131         irc_channel_t *ic;
    132        
    133         if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
    134                 ic = irc_channel_new( irc, cmd[1] );
    135        
    136         if( ic == NULL )
    137         {
    138                 irc_send_num( irc, 479, "%s :Invalid channel name", cmd[1] );
    139                 return;
    140         }
    141        
    142         if( ic->flags & IRC_CHANNEL_JOINED )
    143                 return; /* Dude, you're already there...
    144                            RFC doesn't have any reply for that though? */
    145        
    146         if( ic->f->join && !ic->f->join( ic ) )
    147                 /* The story is: FALSE either means the handler showed an error
    148                    message, or is doing some work before the join should be
    149                    confirmed. (In the latter case, the caller should take care
    150                    of that confirmation.)
    151                    TRUE means all's good, let the user join the channel right away. */
    152                 return;
    153        
    154         irc_channel_add_user( ic, irc->user );
    155 }
    156 
    157 static void irc_cmd_names( irc_t *irc, char **cmd )
    158 {
    159         irc_channel_t *ic;
    160        
    161         if( cmd[1] && ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
    162                 irc_send_names( ic );
    163         /* With no args, we should show /names of all chans. Make the code
    164            below work well if necessary.
    165         else
    166         {
    167                 GSList *l;
    168                
    169                 for( l = irc->channels; l; l = l->next )
    170                         irc_send_names( l->data );
    171         }
    172         */
    173 }
    174 
    175 static void irc_cmd_part( irc_t *irc, char **cmd )
    176 {
    177         irc_channel_t *ic;
    178        
    179         if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
    180         {
    181                 irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
    182         }
    183         else if( irc_channel_del_user( ic, irc->user, FALSE, cmd[2] ) )
    184         {
    185                 if( ic->f->part )
    186                         ic->f->part( ic, NULL );
    187         }
    188         else
    189         {
    190                 irc_send_num( irc, 442, "%s :You're not on that channel", cmd[1] );
    191         }
    192 }
    193 
    194 static void irc_cmd_whois( irc_t *irc, char **cmd )
    195 {
    196         char *nick = cmd[1];
    197         irc_user_t *iu = irc_user_by_name( irc, nick );
    198        
    199         if( iu )
    200                 irc_send_whois( iu );
    201         else
    202                 irc_send_num( irc, 401, "%s :Nick does not exist", nick );
    203 }
    204 
    205 static void irc_cmd_whowas( irc_t *irc, char **cmd )
    206 {
    207         /* For some reason irssi tries a whowas when whois fails. We can
    208            ignore this, but then the user never gets a "user not found"
    209            message from irssi which is a bit annoying. So just respond
    210            with not-found and irssi users will get better error messages */
    211        
    212         irc_send_num( irc, 406, "%s :Nick does not exist", cmd[1] );
    213         irc_send_num( irc, 369, "%s :End of WHOWAS", cmd[1] );
    214 }
    215 
    216 static void irc_cmd_motd( irc_t *irc, char **cmd )
    217 {
    218         irc_send_motd( irc );
     117        irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost );
     118}
     119
     120static void irc_cmd_oper( irc_t *irc, char **cmd )
     121{
     122        if( global.conf->oper_pass &&
     123            ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ?
     124                md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 :
     125                strcmp( cmd[2], global.conf->oper_pass ) == 0 ) )
     126        {
     127                irc_umode_set( irc, "+o", 1 );
     128                irc_reply( irc, 381, ":Password accepted" );
     129        }
     130        else
     131        {
     132                irc_reply( irc, 432, ":Incorrect password" );
     133        }
    219134}
    220135
    221136static void irc_cmd_mode( irc_t *irc, char **cmd )
    222137{
    223         if( irc_channel_name_ok( cmd[1] ) )
    224         {
    225                 irc_channel_t *ic;
    226                
    227                 if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
    228                         irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
    229                 else if( cmd[2] )
     138        if( strchr( CTYPES, *cmd[1] ) )
     139        {
     140                if( cmd[2] )
    230141                {
    231142                        if( *cmd[2] == '+' || *cmd[2] == '-' )
    232                                 irc_send_num( irc, 477, "%s :Can't change channel modes", cmd[1] );
     143                                irc_reply( irc, 477, "%s :Can't change channel modes", cmd[1] );
    233144                        else if( *cmd[2] == 'b' )
    234                                 irc_send_num( irc, 368, "%s :No bans possible", cmd[1] );
     145                                irc_reply( irc, 368, "%s :No bans possible", cmd[1] );
    235146                }
    236147                else
    237                         irc_send_num( irc, 324, "%s +%s", cmd[1], ic->mode );
    238         }
    239         else
    240         {
    241                 if( nick_cmp( cmd[1], irc->user->nick ) == 0 )
     148                        irc_reply( irc, 324, "%s +%s", cmd[1], CMODE );
     149        }
     150        else
     151        {
     152                if( nick_cmp( cmd[1], irc->nick ) == 0 )
    242153                {
    243154                        if( cmd[2] )
    244155                                irc_umode_set( irc, cmd[2], 0 );
    245156                        else
    246                                 irc_send_num( irc, 221, "+%s", irc->umode );
     157                                irc_reply( irc, 221, "+%s", irc->umode );
    247158                }
    248159                else
    249                         irc_send_num( irc, 502, ":Don't touch their modes" );
    250         }
    251 }
    252 
    253 static void irc_cmd_who( irc_t *irc, char **cmd )
    254 {
    255         char *channel = cmd[1];
    256         irc_channel_t *ic;
    257        
    258         if( !channel || *channel == '0' || *channel == '*' || !*channel )
    259                 irc_send_who( irc, irc->users, "**" );
    260         else if( ( ic = irc_channel_by_name( irc, channel ) ) )
    261                 irc_send_who( irc, ic->users, channel );
    262         else
    263                 irc_send_num( irc, 403, "%s :No such channel", channel );
     160                        irc_reply( irc, 502, ":Don't touch their modes" );
     161        }
     162}
     163
     164static void irc_cmd_names( irc_t *irc, char **cmd )
     165{
     166        irc_names( irc, cmd[1]?cmd[1]:irc->channel );
     167}
     168
     169static void irc_cmd_part( irc_t *irc, char **cmd )
     170{
     171        struct groupchat *c;
     172       
     173        if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
     174        {
     175                user_t *u = user_find( irc, irc->nick );
     176               
     177                /* Not allowed to leave control channel */
     178                irc_part( irc, u, irc->channel );
     179                irc_join( irc, u, irc->channel );
     180        }
     181        else if( ( c = irc_chat_by_channel( irc, cmd[1] ) ) )
     182        {
     183                user_t *u = user_find( irc, irc->nick );
     184               
     185                irc_part( irc, u, c->channel );
     186               
     187                if( c->ic )
     188                {
     189                        c->joined = 0;
     190                        c->ic->acc->prpl->chat_leave( c );
     191                }
     192        }
     193        else
     194        {
     195                irc_reply( irc, 403, "%s :No such channel", cmd[1] );
     196        }
     197}
     198
     199static void irc_cmd_join( irc_t *irc, char **cmd )
     200{
     201        if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
     202                ; /* Dude, you're already there...
     203                     RFC doesn't have any reply for that though? */
     204        else if( cmd[1] )
     205        {
     206                struct chat *c;
     207               
     208                if( strchr( CTYPES, cmd[1][0] ) == NULL || cmd[1][1] == 0 )
     209                        irc_reply( irc, 479, "%s :Invalid channel name", cmd[1] );
     210                else if( ( c = chat_bychannel( irc, cmd[1] ) ) && c->acc && c->acc->ic )
     211                        chat_join( irc, c, cmd[2] );
     212                else
     213                        irc_reply( irc, 403, "%s :No such channel", cmd[1] );
     214        }
     215}
     216
     217static void irc_cmd_invite( irc_t *irc, char **cmd )
     218{
     219        char *nick = cmd[1], *channel = cmd[2];
     220        struct groupchat *c = irc_chat_by_channel( irc, channel );
     221        user_t *u = user_find( irc, nick );
     222       
     223        if( u && c && ( u->ic == c->ic ) )
     224                if( c->ic && c->ic->acc->prpl->chat_invite )
     225                {
     226                        c->ic->acc->prpl->chat_invite( c, u->handle, NULL );
     227                        irc_reply( irc, 341, "%s %s", nick, channel );
     228                        return;
     229                }
     230       
     231        irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
    264232}
    265233
    266234static void irc_cmd_privmsg( irc_t *irc, char **cmd )
    267235{
    268         irc_channel_t *ic;
    269         irc_user_t *iu;
    270        
    271         if( !cmd[2] )
    272         {
    273                 irc_send_num( irc, 412, ":No text to send" );
    274                 return;
    275         }
    276        
    277         /* Don't treat CTCP actions as real CTCPs, just convert them right now. */
    278         if( g_strncasecmp( cmd[2], "\001ACTION", 7 ) == 0 )
    279         {
    280                 cmd[2] += 4;
    281                 strcpy( cmd[2], "/me" );
    282                 if( cmd[2][strlen(cmd[2])-1] == '\001' )
    283                         cmd[2][strlen(cmd[2])-1] = '\0';
    284         }
    285        
    286         if( irc_channel_name_ok( cmd[1] ) &&
    287             ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
    288         {
    289                 if( ic->f->privmsg )
    290                         ic->f->privmsg( ic, cmd[2] );
    291         }
    292         else if( ( iu = irc_user_by_name( irc, cmd[1] ) ) )
    293         {
    294                 if( cmd[2][0] == '\001' )
    295                 {
    296                         char **ctcp;
    297                        
    298                         if( iu->f->ctcp == NULL )
    299                                 return;
    300                         if( cmd[2][strlen(cmd[2])-1] == '\001' )
    301                                 cmd[2][strlen(cmd[2])-1] = '\0';
    302                        
    303                         ctcp = split_command_parts( cmd[2] + 1 );
    304                         iu->f->ctcp( iu, ctcp );
    305                 }
    306                 else if( iu->f->privmsg )
    307                 {
    308                         iu->flags |= IRC_USER_PRIVATE;
    309                         iu->f->privmsg( iu, cmd[2] );
    310                 }
    311         }
    312         else
    313         {
    314                 irc_send_num( irc, 401, "%s :No such nick/channel", cmd[1] );
    315         }
    316 
    317 
    318 #if 0
    319         else if( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 )
    320         {
     236        if ( !cmd[2] )
     237        {
     238                irc_reply( irc, 412, ":No text to send" );
     239        }
     240        else if ( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 )
     241        {
     242                irc_write( irc, ":%s!%s@%s %s %s :%s", irc->nick, irc->user, irc->host, cmd[0], cmd[1], cmd[2] );
    321243        }
    322244        else
     
    359281                irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? OPT_AWAY : 0 );
    360282        }
    361 #endif
    362 }
    363 
    364 static void irc_cmd_nickserv( irc_t *irc, char **cmd )
    365 {
    366         /* [SH] This aliases the NickServ command to PRIVMSG root */
    367         /* [TV] This aliases the NS command to PRIVMSG root as well */
    368         root_command( irc, cmd + 1 );
    369 }
    370 
    371 
    372 
    373 static void irc_cmd_oper( irc_t *irc, char **cmd )
    374 {
    375         if( global.conf->oper_pass &&
    376             ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ?
    377                 md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 :
    378                 strcmp( cmd[2], global.conf->oper_pass ) == 0 ) )
    379         {
    380                 irc_umode_set( irc, "+o", 1 );
    381                 irc_send_num( irc, 381, ":Password accepted" );
    382         }
    383         else
    384         {
    385                 irc_send_num( irc, 432, ":Incorrect password" );
    386         }
    387 }
    388 
    389 static void irc_cmd_invite( irc_t *irc, char **cmd )
    390 {
    391         irc_channel_t *ic;
    392         irc_user_t *iu;
    393        
    394         if( ( iu = irc_user_by_name( irc, cmd[1] ) ) == NULL )
    395         {
    396                 irc_send_num( irc, 401, "%s :No such nick", cmd[1] );
    397                 return;
    398         }
    399         else if( ( ic = irc_channel_by_name( irc, cmd[2] ) ) == NULL )
    400         {
    401                 irc_send_num( irc, 403, "%s :No such channel", cmd[2] );
    402                 return;
    403         }
    404        
    405         if( !ic->f->invite || !ic->f->invite( ic, iu ) )
    406                 irc_send_num( irc, 482, "%s :Can't invite people here", cmd[2] );
     283}
     284
     285static void irc_cmd_who( irc_t *irc, char **cmd )
     286{
     287        char *channel = cmd[1];
     288        user_t *u = irc->users;
     289        struct groupchat *c;
     290        GList *l;
     291       
     292        if( !channel || *channel == '0' || *channel == '*' || !*channel )
     293                while( u )
     294                {
     295                        irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", u->online ? irc->channel : "*", u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
     296                        u = u->next;
     297                }
     298        else if( g_strcasecmp( channel, irc->channel ) == 0 )
     299                while( u )
     300                {
     301                        if( u->online )
     302                                irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
     303                        u = u->next;
     304                }
     305        else if( ( c = irc_chat_by_channel( irc, channel ) ) )
     306                for( l = c->in_room; l; l = l->next )
     307                {
     308                        if( ( u = user_findhandle( c->ic, l->data ) ) )
     309                                irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
     310                }
     311        else if( ( u = user_find( irc, channel ) ) )
     312                irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
     313       
     314        irc_reply( irc, 315, "%s :End of /WHO list", channel?channel:"**" );
    407315}
    408316
    409317static void irc_cmd_userhost( irc_t *irc, char **cmd )
    410318{
     319        user_t *u;
    411320        int i;
    412321       
     
    418327       
    419328        for( i = 1; cmd[i]; i ++ )
    420         {
    421                 irc_user_t *iu = irc_user_by_name( irc, cmd[i] );
    422                
    423                 if( iu )
    424                         irc_send_num( irc, 302, ":%s=%c%s@%s", iu->nick,
    425                                       irc_user_get_away( iu ) ? '-' : '+',
    426                                       iu->user, iu->host );
    427         }
     329                if( ( u = user_find( irc, cmd[i] ) ) )
     330                {
     331                        if( u->online && u->away )
     332                                irc_reply( irc, 302, ":%s=-%s@%s", u->nick, u->user, u->host );
     333                        else
     334                                irc_reply( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host );
     335                }
    428336}
    429337
    430338static void irc_cmd_ison( irc_t *irc, char **cmd )
    431339{
     340        user_t *u;
    432341        char buff[IRC_MAX_LINE];
    433342        int lenleft, i;
     
    445354                while( *this )
    446355                {
    447                         irc_user_t *iu;
    448                        
    449356                        if( ( next = strchr( this, ' ' ) ) )
    450357                                *next = 0;
    451358                       
    452                         if( ( iu = irc_user_by_name( irc, this ) ) &&
    453                             iu->bu && iu->bu->flags & BEE_USER_ONLINE )
    454                         {
    455                                 lenleft -= strlen( iu->nick ) + 1;
     359                        if( ( u = user_find( irc, this ) ) && u->online )
     360                        {
     361                                lenleft -= strlen( u->nick ) + 1;
    456362                               
    457363                                if( lenleft < 0 )
    458364                                        break;
    459365                               
    460                                 strcat( buff, iu->nick );
     366                                strcat( buff, u->nick );
    461367                                strcat( buff, " " );
    462368                        }
     
    481387                buff[strlen(buff)-1] = '\0';
    482388       
    483         irc_send_num( irc, 303, ":%s", buff );
     389        irc_reply( irc, 303, ":%s", buff );
    484390}
    485391
     
    494400        {
    495401                char *nick;
    496                 irc_user_t *iu;
     402                user_t *u;
    497403               
    498404                if( !cmd[i][0] || !cmd[i][1] )
     
    502408                nick_lc( nick );
    503409               
    504                 iu = irc_user_by_name( irc, nick );
     410                u = user_find( irc, nick );
    505411               
    506412                if( cmd[i][0] == '+' )
     
    509415                                g_hash_table_insert( irc->watches, nick, nick );
    510416                       
    511                         if( iu && iu->bu && iu->bu->flags & BEE_USER_ONLINE )
    512                                 irc_send_num( irc, 604, "%s %s %s %d :%s", iu->nick, iu->user,
    513                                               iu->host, (int) time( NULL ), "is online" );
     417                        if( u && u->online )
     418                                irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "is online" );
    514419                        else
    515                                 irc_send_num( irc, 605, "%s %s %s %d :%s", nick, "*", "*",
    516                                               (int) time( NULL ), "is offline" );
     420                                irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", (int) time( NULL ), "is offline" );
    517421                }
    518422                else if( cmd[i][0] == '-' )
     
    525429                                g_free( okey );
    526430                               
    527                                 irc_send_num( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
     431                                irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
    528432                        }
    529433                }
     
    533437static void irc_cmd_topic( irc_t *irc, char **cmd )
    534438{
    535         irc_channel_t *ic = irc_channel_by_name( irc, cmd[1] );
    536         const char *new = cmd[2];
    537        
    538         if( ic == NULL )
    539         {
    540                 irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
    541         }
    542         else if( new )
    543         {
    544                 if( ic->f->topic == NULL )
    545                         irc_send_num( irc, 482, "%s :Can't change this channel's topic", ic->name );
    546                 else if( ic->f->topic( ic, new ) )
    547                         irc_send_topic( ic, TRUE );
    548         }
    549         else
    550         {
    551                 irc_send_topic( ic, FALSE );
     439        char *channel = cmd[1];
     440        char *topic = cmd[2];
     441       
     442        if( topic )
     443        {
     444                /* Send the topic */
     445                struct groupchat *c = irc_chat_by_channel( irc, channel );
     446                if( c && c->ic && c->ic->acc->prpl->chat_topic )
     447                        c->ic->acc->prpl->chat_topic( c, topic );
     448        }
     449        else
     450        {
     451                /* Get the topic */
     452                irc_topic( irc, channel );
    552453        }
    553454}
     
    555456static void irc_cmd_away( irc_t *irc, char **cmd )
    556457{
    557         if( cmd[1] && *cmd[1] )
    558         {
    559                 char away[strlen(cmd[1])+1];
     458        user_t *u = user_find( irc, irc->nick );
     459        char *away = cmd[1];
     460       
     461        if( !u ) return;
     462       
     463        if( away && *away )
     464        {
    560465                int i, j;
    561466               
    562467                /* Copy away string, but skip control chars. Mainly because
    563468                   Jabber really doesn't like them. */
    564                 for( i = j = 0; cmd[1][i]; i ++ )
    565                         if( ( away[j] = cmd[1][i] ) >= ' ' )
     469                u->away = g_malloc( strlen( away ) + 1 );
     470                for( i = j = 0; away[i]; i ++ )
     471                        if( ( u->away[j] = away[i] ) >= ' ' )
    566472                                j ++;
    567                 away[j] = '\0';
    568                
    569                 irc_send_num( irc, 306, ":You're now away: %s", away );
    570                 set_setstr( &irc->b->set, "away", away );
    571         }
    572         else
    573         {
    574                 irc_send_num( irc, 305, ":Welcome back" );
    575                 set_setstr( &irc->b->set, "away", NULL );
    576         }
     473                u->away[j] = 0;
     474               
     475                irc_reply( irc, 306, ":You're now away: %s", u->away );
     476                /* irc_umode_set( irc, irc->myhost, "+a" ); */
     477        }
     478        else
     479        {
     480                if( u->away ) g_free( u->away );
     481                u->away = NULL;
     482                /* irc_umode_set( irc, irc->myhost, "-a" ); */
     483                irc_reply( irc, 305, ":Welcome back" );
     484        }
     485       
     486        set_setstr( &irc->set, "away", u->away );
     487}
     488
     489static void irc_cmd_whois( irc_t *irc, char **cmd )
     490{
     491        char *nick = cmd[1];
     492        user_t *u = user_find( irc, nick );
     493       
     494        if( u )
     495        {
     496                irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname );
     497               
     498                if( u->ic )
     499                        irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->ic->acc->user,
     500                                   u->ic->acc->server && *u->ic->acc->server ? u->ic->acc->server : "",
     501                                   u->ic->acc->prpl->name );
     502                else
     503                        irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO );
     504               
     505                if( !u->online )
     506                        irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
     507                else if( u->away )
     508                        irc_reply( irc, 301, "%s :%s", u->nick, u->away );
     509                if( u->status_msg )
     510                        irc_reply( irc, 320, "%s :%s", u->nick, u->status_msg );
     511               
     512                irc_reply( irc, 318, "%s :End of /WHOIS list", nick );
     513        }
     514        else
     515        {
     516                irc_reply( irc, 401, "%s :Nick does not exist", nick );
     517        }
     518}
     519
     520static void irc_cmd_whowas( irc_t *irc, char **cmd )
     521{
     522        /* For some reason irssi tries a whowas when whois fails. We can
     523           ignore this, but then the user never gets a "user not found"
     524           message from irssi which is a bit annoying. So just respond
     525           with not-found and irssi users will get better error messages */
     526       
     527        irc_reply( irc, 406, "%s :Nick does not exist", cmd[1] );
     528        irc_reply( irc, 369, "%s :End of WHOWAS", cmd[1] );
     529}
     530
     531static void irc_cmd_nickserv( irc_t *irc, char **cmd )
     532{
     533        /* [SH] This aliases the NickServ command to PRIVMSG root */
     534        /* [TV] This aliases the NS command to PRIVMSG root as well */
     535        root_command( irc, cmd + 1 );
     536}
     537
     538static void irc_cmd_motd( irc_t *irc, char **cmd )
     539{
     540        irc_motd( irc );
     541}
     542
     543static void irc_cmd_pong( irc_t *irc, char **cmd )
     544{
     545        /* We could check the value we get back from the user, but in
     546           fact we don't care, we're just happy he's still alive. */
     547        irc->last_pong = gettime();
     548        irc->pinging = 0;
    577549}
    578550
    579551static void irc_cmd_version( irc_t *irc, char **cmd )
    580552{
    581         irc_send_num( irc, 351, "bitlbee-%s. %s :%s/%s ",
    582                       BITLBEE_VERSION, irc->root->host, ARCH, CPU );
     553        irc_reply( irc, 351, "bitlbee-%s. %s :%s/%s ", BITLBEE_VERSION, irc->myhost, ARCH, CPU );
    583554}
    584555
    585556static void irc_cmd_completions( irc_t *irc, char **cmd )
    586557{
     558        user_t *u = user_find( irc, irc->mynick );
    587559        help_t *h;
    588560        set_t *s;
    589561        int i;
    590562       
    591         irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS OK" );
     563        irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" );
    592564       
    593565        for( i = 0; commands[i].command; i ++ )
    594                 irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS %s", commands[i].command );
     566                irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command );
    595567       
    596568        for( h = global.help; h; h = h->next )
    597                 irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS help %s", h->title );
    598        
    599         for( s = irc->b->set; s; s = s->next )
    600                 irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS set %s", s->key );
    601        
    602         irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS END" );
     569                irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->title );
     570       
     571        for( s = irc->set; s; s = s->next )
     572                irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS set ", s->key );
     573       
     574        irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "END" );
    603575}
    604576
     
    610582                ipc_to_master( cmd );
    611583       
    612         irc_send_num( irc, 382, "%s :Rehashing", global.conf_file );
     584        irc_reply( irc, 382, "%s :Rehashing", global.conf_file );
    613585}
    614586
     
    619591        { "quit",        0, irc_cmd_quit,        0 },
    620592        { "ping",        0, irc_cmd_ping,        0 },
    621         { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
     593        { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
     594        { "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
     595        { "names",       0, irc_cmd_names,       IRC_CMD_LOGGED_IN },
     596        { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
    622597        { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
    623         { "names",       1, irc_cmd_names,       IRC_CMD_LOGGED_IN },
    624         { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
    625         { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
    626         { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
    627         { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
    628         { "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
     598        { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
     599        { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
     600        { "notice",      1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
    629601        { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
    630         { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
    631         { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
    632         { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
    633         { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
    634         { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
    635         { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
    636602        { "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
    637603        { "ison",        1, irc_cmd_ison,        IRC_CMD_LOGGED_IN },
    638604        { "watch",       1, irc_cmd_watch,       IRC_CMD_LOGGED_IN },
    639         { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
    640 #if 0
    641         { "notice",      1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
    642 #endif
    643605        { "topic",       1, irc_cmd_topic,       IRC_CMD_LOGGED_IN },
    644         { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
     606        { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
     607        { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
     608        { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
     609        { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
     610        { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
     611        { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
     612        { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
     613        { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
     614        { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
    645615        { "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
    646616        { "deaf",        0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
     
    668638                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
    669639                        {
    670                                 irc_send_num( irc, 462, ":Only allowed before logging in" );
     640                                irc_reply( irc, 462, ":Only allowed before logging in" );
    671641                        }
    672642                        else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
    673643                        {
    674                                 irc_send_num( irc, 451, ":Register first" );
     644                                irc_reply( irc, 451, ":Register first" );
    675645                        }
    676646                        else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
    677647                        {
    678                                 irc_send_num( irc, 481, ":Permission denied - You're not an IRC operator" );
     648                                irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" );
    679649                        }
    680650                        else if( n_arg < irc_commands[i].required_parameters )
    681651                        {
    682                                 irc_send_num( irc, 461, "%s :Need more parameters", cmd[0] );
     652                                irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
    683653                        }
    684654                        else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
     
    697667       
    698668        if( irc->status >= USTATUS_LOGGED_IN )
    699                 irc_send_num( irc, 421, "%s :Unknown command", cmd[0] );
    700 }
     669                irc_reply( irc, 421, "%s :Unknown command", cmd[0] );
     670}
  • lib/misc.c

    rf1cea66 r560d0a0  
    647647        return ret;
    648648}
    649 
    650 char **split_command_parts( char *command )
    651 {
    652         static char *cmd[IRC_MAX_ARGS+1];
    653         char *s, q = 0;
    654         int k;
    655        
    656         memset( cmd, 0, sizeof( cmd ) );
    657         cmd[0] = command;
    658         k = 1;
    659         for( s = command; *s && k < IRC_MAX_ARGS; s ++ )
    660                 if( *s == ' ' && !q )
    661                 {
    662                         *s = 0;
    663                         while( *++s == ' ' );
    664                         if( *s == '"' || *s == '\'' )
    665                         {
    666                                 q = *s;
    667                                 s ++;
    668                         }
    669                         if( *s )
    670                         {
    671                                 cmd[k++] = s;
    672                                 s --;
    673                         }
    674                         else
    675                         {
    676                                 break;
    677                         }
    678                 }
    679                 else if( *s == '\\' && ( ( !q && s[1] ) || ( q && q == s[1] ) ) )
    680                 {
    681                         char *cpy;
    682                        
    683                         for( cpy = s; *cpy; cpy ++ )
    684                                 cpy[0] = cpy[1];
    685                 }
    686                 else if( *s == q )
    687                 {
    688                         q = *s = 0;
    689                 }
    690        
    691         /* Full zero-padding for easier argc checking. */
    692         while( k <= IRC_MAX_ARGS )
    693                 cmd[k++] = NULL;
    694        
    695         return cmd;
    696 }
  • lib/misc.h

    rf1cea66 r560d0a0  
    6969G_MODULE_EXPORT int md5_verify_password( char *password, char *hash );
    7070
    71 G_MODULE_EXPORT char **split_command_parts( char *command );
    72 
    7371#endif
  • nick.c

    rf1cea66 r560d0a0  
    7878               
    7979                nick_strip( nick );
    80                 if( set_getbool( &acc->bee->set, "lcnicks" ) )
     80                if( set_getbool( &acc->irc->set, "lcnicks" ) )
    8181                        nick_lc( nick );
    8282        }
     
    9292void nick_dedupe( account_t *acc, const char *handle, char nick[MAX_NICK_LENGTH+1] )
    9393{
    94         irc_t *irc = (irc_t*) acc->bee->ui_data;
    9594        int inf_protection = 256;
    9695       
    9796        /* Now, find out if the nick is already in use at the moment, and make
    9897           subtle changes to make it unique. */
    99         while( !nick_ok( nick ) || irc_user_by_name( irc, nick ) )
     98        while( !nick_ok( nick ) || user_find( acc->irc, nick ) )
    10099        {
    101100                if( strlen( nick ) < ( MAX_NICK_LENGTH - 1 ) )
     
    113112                        int i;
    114113                       
    115                         irc_usermsg( irc, "Warning: Almost had an infinite loop in nick_get()! "
    116                                           "This used to be a fatal BitlBee bug, but we tried to fix it. "
    117                                           "This message should *never* appear anymore. "
    118                                           "If it does, please *do* send us a bug report! "
    119                                           "Please send all the following lines in your report:" );
    120                        
    121                         irc_usermsg( irc, "Trying to get a sane nick for handle %s", handle );
     114                        irc_usermsg( acc->irc, "Warning: Almost had an infinite loop in nick_get()! "
     115                                               "This used to be a fatal BitlBee bug, but we tried to fix it. "
     116                                               "This message should *never* appear anymore. "
     117                                               "If it does, please *do* send us a bug report! "
     118                                               "Please send all the following lines in your report:" );
     119                       
     120                        irc_usermsg( acc->irc, "Trying to get a sane nick for handle %s", handle );
    122121                        for( i = 0; i < MAX_NICK_LENGTH; i ++ )
    123                                 irc_usermsg( irc, "Char %d: %c/%d", i, nick[i], nick[i] );
    124                        
    125                         irc_usermsg( irc, "FAILED. Returning an insane nick now. Things might break. "
    126                                           "Good luck, and please don't forget to paste the lines up here "
    127                                           "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
     122                                irc_usermsg( acc->irc, "Char %d: %c/%d", i, nick[i], nick[i] );
     123                       
     124                        irc_usermsg( acc->irc, "FAILED. Returning an insane nick now. Things might break. "
     125                                               "Good luck, and please don't forget to paste the lines up here "
     126                                               "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
    128127                       
    129128                        g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() );
  • protocols/Makefile

    rf1cea66 r560d0a0  
    1313
    1414# [SH] Program variables
    15 objects = account.o bee.o bee_chat.o bee_ft.o bee_user.o nogaim.o
    16 
     15objects = nogaim.o
    1716
    1817# [SH] The next two lines should contain the directory name (in $(subdirs))
  • protocols/ft.h

    rf1cea66 r560d0a0  
    107107         */
    108108        gpointer data;
    109         struct im_connection *ic;
    110109       
    111110        /*
     
    169168 * the canceled() and free() callbacks given in file will be called by this function.
    170169 */
    171 void imcb_file_canceled( struct im_connection *ic, file_transfer_t *file, char *reason );
     170void imcb_file_canceled( file_transfer_t *file, char *reason );
    172171
    173 gboolean imcb_file_recv_start( struct im_connection *ic, file_transfer_t *ft );
     172gboolean imcb_file_recv_start( file_transfer_t *ft );
    174173
    175 void imcb_file_finished( struct im_connection *ic, file_transfer_t *file );
     174void imcb_file_finished( file_transfer_t *file );
    176175#endif
  • protocols/jabber/conference.c

    rf1cea66 r560d0a0  
    9292{
    9393        char *normalized = jabber_normalize( name );
    94         GSList *l;
    9594        struct groupchat *ret;
    9695        struct jabber_chat *jc;
    9796       
    98         for( l = ic->groupchats; l; l = l->next )
    99         {
    100                 ret = l->data;
     97        for( ret = ic->groupchats; ret; ret = ret->next )
     98        {
    10199                jc = ret->data;
    102100                if( strcmp( normalized, jc->name ) == 0 )
     
    105103        g_free( normalized );
    106104       
    107         return l ? ret : NULL;
     105        return ret;
    108106}
    109107
  • protocols/jabber/iq.c

    rf1cea66 r560d0a0  
    382382        while( ( c = xt_find_node( c, "item" ) ) )
    383383        {
    384                 struct xt_node *group = xt_find_node( c->children, "group" );
     384                struct xt_node *group = xt_find_node( node->children, "group" );
    385385                char *jid = xt_find_attr( c, "jid" );
    386386                char *name = xt_find_attr( c, "name" );
     
    391391                        if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) )
    392392                        {
    393                                 imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
    394                                                            group->text : NULL );
     393                                if( initial || imcb_find_buddy( ic, jid ) == NULL )
     394                                        imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
     395                                                                   group->text : NULL );
    395396                               
    396397                                if( name )
     
    588589            strcmp( s, "result" ) == 0 )
    589590        {
    590                 if( bee_user_by_handle( ic->bee, ic, jid ) == NULL )
     591                if( imcb_find_buddy( ic, jid ) == NULL )
    591592                        imcb_add_buddy( ic, jid, NULL );
    592593        }
  • protocols/jabber/jabber.c

    rf1cea66 r560d0a0  
    267267       
    268268        while( jd->filetransfers )
    269                 imcb_file_canceled( ic, ( ( struct jabber_transfer *) jd->filetransfers->data )->ft, "Logging out" );
     269                imcb_file_canceled( ( ( struct jabber_transfer *) jd->filetransfers->data )->ft, "Logging out" );
    270270
    271271        while( jd->streamhosts )
     
    282282       
    283283        while( ic->groupchats )
    284                 jabber_chat_free( ic->groupchats->data );
     284                jabber_chat_free( ic->groupchats );
    285285       
    286286        if( jd->r_inpa >= 0 )
  • protocols/jabber/jabber_util.c

    rf1cea66 r560d0a0  
    279279        presence_send_request( bla->ic, bla->handle, "subscribed" );
    280280       
    281         imcb_ask_add( bla->ic, bla->handle, NULL );
     281        if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
     282                imcb_ask_add( bla->ic, bla->handle, NULL );
    282283       
    283284        g_free( bla->handle );
     
    461462               
    462463                if( bud == NULL && ( flags & GET_BUDDY_CREAT ) &&
    463                     ( bare_exists || bee_user_by_handle( ic->bee, ic, jid ) ) )
     464                    ( bare_exists || imcb_find_buddy( ic, jid ) ) )
    464465                {
    465466                        *s = '/';
     
    482483                if( bud == NULL )
    483484                        /* No match. Create it now? */
    484                         return ( ( flags & GET_BUDDY_CREAT ) &&
    485                                  bee_user_by_handle( ic->bee, ic, jid_ ) ) ?
     485                        return ( ( flags & GET_BUDDY_CREAT ) && imcb_find_buddy( ic, jid_ ) ) ?
    486486                                   jabber_buddy_add( ic, jid_ ) : NULL;
    487487                else if( bud->resource && ( flags & GET_BUDDY_EXACT ) )
  • protocols/jabber/presence.c

    rf1cea66 r560d0a0  
    205205        struct jabber_data *jd = ic->proto_data;
    206206        struct xt_node *node, *cap;
    207         GSList *l;
     207        struct groupchat *c;
    208208        int st;
    209209       
     
    229229        /* Have to send this update to all groupchats too, the server won't
    230230           do this automatically. */
    231         for( l = ic->groupchats; l && st; l = l->next )
    232         {
    233                 struct groupchat *c = l->data;
     231        for( c = ic->groupchats; c && st; c = c->next )
     232        {
    234233                struct jabber_chat *jc = c->data;
    235234               
  • protocols/jabber/s5bytestream.c

    rf1cea66 r560d0a0  
    567567        xt_free_node( reply );
    568568
    569         imcb_file_canceled( tf->ic, tf->ft, "couldn't connect to any streamhosts" );
     569        imcb_file_canceled( tf->ft, "couldn't connect to any streamhosts" );
    570570
    571571        bt->tf->watch_in = 0;
     
    604604               
    605605        if( !jabber_write_packet( tf->ic, reply ) )
    606                 imcb_file_canceled( tf->ic, tf->ft, "Error transmitting bytestream response" );
     606                imcb_file_canceled( tf->ft, "Error transmitting bytestream response" );
    607607        xt_free_node( reply );
    608608}
     
    644644
    645645        if( tf->bytesread >= tf->ft->file_size )
    646                 imcb_file_finished( tf->ic, tf->ft );
     646                imcb_file_finished( tf->ft );
    647647
    648648        tf->ft->write( tf->ft, tf->ft->buffer, ret );   
     
    660660        if( tf->watch_in )
    661661        {
    662                 imcb_file_canceled( tf->ic, ft, "BUG in jabber file transfer: write_request called when already watching for input" );
     662                imcb_file_canceled( ft, "BUG in jabber file transfer: write_request called when already watching for input" );
    663663                return FALSE;
    664664        }
     
    706706
    707707        if( tf->byteswritten >= ft->file_size )
    708                 imcb_file_finished( tf->ic, ft );
     708                imcb_file_finished( ft );
    709709        else
    710710                bt->tf->watch_out = b_input_add( tf->fd, B_EV_IO_WRITE, jabber_bs_send_can_write, bt );
     
    10061006
    10071007        if( !jabber_write_packet( tf->ic, iq ) )
    1008                 imcb_file_canceled( tf->ic, tf->ft, "Error transmitting bytestream request" );
     1008                imcb_file_canceled( tf->ft, "Error transmitting bytestream request" );
    10091009        return TRUE;
    10101010}
     
    10211021
    10221022        if( jd->streamhosts==NULL ) /* we're done here unless we have a proxy to try */
    1023                 imcb_file_canceled( tf->ic, tf->ft, error );
     1023                imcb_file_canceled( tf->ft, error );
    10241024
    10251025        /* MUST always return FALSE! */
  • protocols/jabber/si.c

    rf1cea66 r560d0a0  
    9191
    9292        if( !foundft )
    93                 imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature file transfers" );
     93                imcb_file_canceled( tf->ft, "Buddy's client doesn't feature file transfers" );
    9494        else if( !foundbt )
    95                 imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature byte streams (required)" );
     95                imcb_file_canceled( tf->ft, "Buddy's client doesn't feature byte streams (required)" );
    9696        else if( !foundsi )
    97                 imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature stream initiation (required)" );
     97                imcb_file_canceled( tf->ft, "Buddy's client doesn't feature stream initiation (required)" );
    9898               
    9999        return foundft && foundbt && foundsi;
     
    109109
    110110        /* and start the receive logic */
    111         imcb_file_recv_start( tf->ic, tf->ft );
     111        imcb_file_recv_start( tf->ft );
    112112
    113113}
     
    156156        if( bud == NULL )
    157157        {
    158                 imcb_file_canceled( ic, ft, "Couldn't find buddy (BUG?)" );
     158                imcb_file_canceled( ft, "Couldn't find buddy (BUG?)" );
    159159                return;
    160160        }
  • protocols/msn/Makefile

    rf1cea66 r560d0a0  
    1313
    1414# [SH] Program variables
    15 objects = msn.o msn_util.o ns.o passport.o sb.o tables.o
     15objects = invitation.o msn.o msn_util.o ns.o passport.o sb.o tables.o
    1616
    1717CFLAGS += -Wall
  • protocols/msn/msn.c

    rf1cea66 r560d0a0  
    7979        if( md )
    8080        {
    81                 /** Disabling MSN ft support for now.
    8281                while( md->filetransfers ) {
    8382                        imcb_file_canceled( md->filetransfers->data, "Closing connection" );
    8483                }
    85                 */
    8684               
    8785                if( md->fd >= 0 )
     
    223221{
    224222        struct msn_switchboard *sb;
    225         struct groupchat *c = imcb_chat_new( ic, who );
    226223       
    227224        if( ( sb = msn_sb_by_handle( ic, who ) ) )
     
    241238                msn_sb_write_msg( ic, m );
    242239
    243                 return c;
    244         }
     240                return NULL;
     241        }
     242       
     243        return NULL;
    245244}
    246245
     
    333332        ret->send_typing = msn_send_typing;
    334333        ret->handle_cmp = g_strcasecmp;
    335         //ret->transfer_request = msn_ftp_transfer_request;
     334        ret->transfer_request = msn_ftp_transfer_request;
    336335
    337336        register_protocol(ret);
  • protocols/msn/msn_util.c

    rf1cea66 r560d0a0  
    9696        msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname );
    9797       
    98         imcb_ask_add( bla->ic, bla->handle, NULL );
     98        if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
     99                imcb_ask_add( bla->ic, bla->handle, NULL );
    99100       
    100101        g_free( bla->handle );
  • protocols/msn/sb.c

    rf1cea66 r560d0a0  
    175175                        i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user );
    176176                }
     177                else if( strncmp( text, MSN_INVITE_HEADERS, sizeof( MSN_INVITE_HEADERS ) - 1 ) == 0 )
     178                {
     179                        buf = g_strdup( text );
     180                        i = strlen( buf );
     181                }
    177182                else if( strcmp( text, SB_KEEPALIVE_MESSAGE ) == 0 )
    178183                {
    179184                        buf = g_strdup( SB_KEEPALIVE_HEADERS );
    180                         i = strlen( buf );
    181                 }
    182                 else if( strncmp( text, MSN_INVITE_HEADERS, sizeof( MSN_INVITE_HEADERS ) - 1 ) == 0 )
    183                 {
    184                         buf = g_strdup( text );
    185185                        i = strlen( buf );
    186186                }
     
    233233{
    234234        struct im_connection *ic = sb->ic;
    235         struct groupchat *c = NULL;
    236235        char buf[1024];
    237236       
    238237        /* Create the groupchat structure. */
    239238        g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session );
    240         if( sb->who )
    241                 c = bee_chat_by_title( ic->bee, ic, sb->who );
    242         if( c && !msn_sb_by_chat( c ) )
    243                 sb->chat = c;
    244         else
    245                 sb->chat = imcb_chat_new( ic, buf );
     239        sb->chat = imcb_chat_new( ic, buf );
    246240       
    247241        /* Populate the channel. */
     
    704698                        }
    705699                }
    706 #if 0
    707                 // Disable MSN ft support for now.
    708700                else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 )
    709701                {
     
    738730                        g_free( command );
    739731                }
    740 #endif
    741732                else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 )
    742733                {
     
    774765void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial )
    775766{
    776         bee_user_t *bu;
     767        struct buddy *b;
    777768       
    778769        if( sb && sb->who && sb->keepalive == 0 &&
    779             ( bu = bee_user_by_handle( sb->ic->bee, sb->ic, sb->who ) ) &&
    780             !( bu->flags & BEE_USER_ONLINE ) &&
     770            ( b = imcb_find_buddy( sb->ic, sb->who ) ) && !b->present &&
    781771            set_getbool( &sb->ic->acc->set, "switchboard_keepalives" ) )
    782772        {
  • protocols/nogaim.c

    rf1cea66 r560d0a0  
    3838#include "chat.h"
    3939
     40static int remove_chat_buddy_silent( struct groupchat *b, const char *handle );
     41static char *format_timestamp( irc_t *irc, time_t msg_ts );
     42
    4043GSList *connections;
    4144
     
    8992}
    9093#endif
     94
     95/* nogaim.c */
    9196
    9297GList *protocols = NULL;
     
    124129}
    125130
     131/* nogaim.c */
    126132void nogaim_init()
    127133{
     
    152158        twitter_initmodule();
    153159#endif
    154 
     160       
    155161#ifdef WITH_PURPLE
    156162        purple_initmodule();
     
    164170GSList *get_connections() { return connections; }
    165171
     172/* multi.c */
     173
    166174struct im_connection *imcb_new( account_t *acc )
    167175{
     
    170178        ic = g_new0( struct im_connection, 1 );
    171179       
    172         ic->bee = acc->bee;
     180        ic->irc = acc->irc;
    173181        ic->acc = acc;
    174182        acc->ic = ic;
     
    184192       
    185193        /* Destroy the pointer to this connection from the account list */
    186         for( a = ic->bee->accounts; a; a = a->next )
     194        for( a = ic->irc->accounts; a; a = a->next )
    187195                if( a->ic == ic )
    188196                {
     
    205213        va_end( params );
    206214
    207         if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
    208             ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
     215        if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
     216            ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
    209217                strip_html( text );
    210218       
    211219        /* Try to find a different connection on the same protocol. */
    212         for( a = ic->bee->accounts; a; a = a->next )
     220        for( a = ic->irc->accounts; a; a = a->next )
    213221                if( a->prpl == ic->acc->prpl && a->ic != ic )
    214222                        break;
     
    216224        /* If we found one, include the screenname in the message. */
    217225        if( a )
    218                 /* FIXME(wilmer): ui_log callback or so */
    219                 irc_usermsg( ic->bee->ui_data, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
     226                irc_usermsg( ic->irc, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
    220227        else
    221                 irc_usermsg( ic->bee->ui_data, "%s - %s", ic->acc->prpl->name, text );
     228                irc_usermsg( ic->irc, "%s - %s", ic->acc->prpl->name, text );
    222229       
    223230        g_free( text );
     
    270277void imcb_connected( struct im_connection *ic )
    271278{
     279        irc_t *irc = ic->irc;
     280        struct chat *c;
     281        user_t *u;
     282       
    272283        /* MSN servers sometimes redirect you to a different server and do
    273284           the whole login sequence again, so these "late" calls to this
     
    276287                return;
    277288       
     289        u = user_find( ic->irc, ic->irc->nick );
     290       
    278291        imcb_log( ic, "Logged in" );
    279292       
     
    288301        ic->acc->auto_reconnect_delay = 0;
    289302       
    290         /*
    291303        for( c = irc->chatrooms; c; c = c->next )
    292304        {
     
    297309                        chat_join( irc, c, NULL );
    298310        }
    299         */
    300311}
    301312
     
    305316       
    306317        a->reconnect = 0;
    307         account_on( a->bee, a );
     318        account_on( a->irc, a );
    308319       
    309320        return( FALSE );        /* Only have to run the timeout once */
     
    318329void imc_logout( struct im_connection *ic, int allow_reconnect )
    319330{
    320         bee_t *bee = ic->bee;
     331        irc_t *irc = ic->irc;
     332        user_t *t, *u;
    321333        account_t *a;
    322         GSList *l;
    323334        int delay;
    324335       
     
    340351        ic->away = NULL;
    341352       
    342         for( l = bee->users; l; )
    343         {
    344                 bee_user_t *bu = l->data;
    345                 GSList *next = l->next;
    346                
    347                 if( bu->ic == ic )
    348                         bee_user_free( bee, bu );
    349                
    350                 l = next;
    351         }
    352        
    353         query_del_by_conn( (irc_t*) ic->bee->ui_data, ic );
    354        
    355         for( a = bee->accounts; a; a = a->next )
     353        u = irc->users;
     354        while( u )
     355        {
     356                if( u->ic == ic )
     357                {
     358                        t = u->next;
     359                        user_del( irc, u->nick );
     360                        u = t;
     361                }
     362                else
     363                        u = u->next;
     364        }
     365       
     366        query_del_by_conn( ic->irc, ic );
     367       
     368        for( a = irc->accounts; a; a = a->next )
    356369                if( a->ic == ic )
    357370                        break;
     
    361374                /* Uhm... This is very sick. */
    362375        }
    363         else if( allow_reconnect && set_getbool( &bee->set, "auto_reconnect" ) &&
     376        else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) &&
    364377                 set_getbool( &a->set, "auto_reconnect" ) &&
    365378                 ( delay = account_reconnect_delay( a ) ) > 0 )
     
    372385}
    373386
     387
     388/* dialogs.c */
     389
    374390void imcb_ask( struct im_connection *ic, char *msg, void *data,
    375391               query_callback doit, query_callback dont )
    376392{
    377         query_add( (irc_t *) ic->bee->ui_data, ic, msg, doit, dont, data );
    378 }
     393        query_add( ic->irc, ic, msg, doit, dont, data );
     394}
     395
     396
     397/* list.c */
    379398
    380399void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group )
    381400{
    382         bee_user_t *bu;
    383         bee_t *bee = ic->bee;
    384        
    385         if( !( bu = bee_user_by_handle( bee, ic, handle ) ) )
    386                 bu = bee_user_new( bee, ic, handle, 0 );
    387        
    388         bu->group = bee_group_by_name( bee, group, TRUE );
    389        
    390         if( bee->ui->user_group )
    391                 bee->ui->user_group( bee, bu );
    392 }
    393 
    394 void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *fullname )
    395 {
    396         bee_t *bee = ic->bee;
    397         bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
    398        
    399         if( !bu || !fullname ) return;
    400        
    401         if( !bu->fullname || strcmp( bu->fullname, fullname ) != 0 )
    402         {
    403                 g_free( bu->fullname );
    404                 bu->fullname = g_strdup( fullname );
    405                
    406                 if( bee->ui->user_fullname )
    407                         bee->ui->user_fullname( bee, bu );
     401        user_t *u;
     402        char nick[MAX_NICK_LENGTH+1], *s;
     403        irc_t *irc = ic->irc;
     404       
     405        if( user_findhandle( ic, handle ) )
     406        {
     407                if( set_getbool( &irc->set, "debug" ) )
     408                        imcb_log( ic, "User already exists, ignoring add request: %s", handle );
     409               
     410                return;
     411               
     412                /* Buddy seems to exist already. Let's ignore this request then...
     413                   Eventually subsequent calls to this function *should* be possible
     414                   when a buddy is in multiple groups. But for now BitlBee doesn't
     415                   even support groups so let's silently ignore this for now. */
     416        }
     417       
     418        memset( nick, 0, MAX_NICK_LENGTH + 1 );
     419        strcpy( nick, nick_get( ic->acc, handle ) );
     420       
     421        u = user_add( ic->irc, nick );
     422       
     423//      if( !realname || !*realname ) realname = nick;
     424//      u->realname = g_strdup( realname );
     425       
     426        if( ( s = strchr( handle, '@' ) ) )
     427        {
     428                u->host = g_strdup( s + 1 );
     429                u->user = g_strndup( handle, s - handle );
     430        }
     431        else if( ic->acc->server )
     432        {
     433                u->host = g_strdup( ic->acc->server );
     434                u->user = g_strdup( handle );
     435               
     436                /* s/ /_/ ... important for AOL screennames */
     437                for( s = u->user; *s; s ++ )
     438                        if( *s == ' ' )
     439                                *s = '_';
     440        }
     441        else
     442        {
     443                u->host = g_strdup( ic->acc->prpl->name );
     444                u->user = g_strdup( handle );
     445        }
     446       
     447        u->ic = ic;
     448        u->handle = g_strdup( handle );
     449        if( group ) u->group = g_strdup( group );
     450        u->send_handler = buddy_send_handler;
     451        u->last_typing_notice = 0;
     452}
     453
     454struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle )
     455{
     456        static struct buddy b[1];
     457        user_t *u;
     458       
     459        u = user_findhandle( ic, handle );
     460       
     461        if( !u )
     462                return( NULL );
     463       
     464        memset( b, 0, sizeof( b ) );
     465        strncpy( b->name, handle, 80 );
     466        strncpy( b->show, u->realname, BUDDY_ALIAS_MAXLEN );
     467        b->present = u->online;
     468        b->ic = u->ic;
     469       
     470        return( b );
     471}
     472
     473void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *realname )
     474{
     475        user_t *u = user_findhandle( ic, handle );
     476        char *set;
     477       
     478        if( !u || !realname ) return;
     479       
     480        if( g_strcasecmp( u->realname, realname ) != 0 )
     481        {
     482                if( u->realname != u->nick ) g_free( u->realname );
     483               
     484                u->realname = g_strdup( realname );
     485               
     486                if( ( ic->flags & OPT_LOGGED_IN ) && set_getbool( &ic->irc->set, "display_namechanges" ) )
     487                        imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname );
     488        }
     489       
     490        set = set_getstr( &ic->acc->set, "nick_source" );
     491        if( strcmp( set, "handle" ) != 0 )
     492        {
     493                char *name = g_strdup( realname );
     494               
     495                if( strcmp( set, "first_name" ) == 0 )
     496                {
     497                        int i;
     498                        for( i = 0; name[i] && !isspace( name[i] ); i ++ ) {}
     499                        name[i] = '\0';
     500                }
     501               
     502                imcb_buddy_nick_hint( ic, handle, name );
     503               
     504                g_free( name );
    408505        }
    409506}
     
    411508void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group )
    412509{
    413         bee_user_free( ic->bee, bee_user_by_handle( ic->bee, ic, handle ) );
     510        user_t *u;
     511       
     512        if( ( u = user_findhandle( ic, handle ) ) )
     513                user_del( ic->irc, u->nick );
    414514}
    415515
     
    418518void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick )
    419519{
    420         bee_t *bee = ic->bee;
    421         bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
    422        
    423         if( !bu || !nick ) return;
    424        
    425         if( bee->ui->user_nick_hint )
    426                 bee->ui->user_nick_hint( bee, bu, nick );
     520        user_t *u = user_findhandle( ic, handle );
     521        char newnick[MAX_NICK_LENGTH+1], *orig_nick;
     522       
     523        if( u && !u->online && !nick_saved( ic->acc, handle ) )
     524        {
     525                /* Only do this if the person isn't online yet (which should
     526                   be the case if we just added it) and if the user hasn't
     527                   assigned a nickname to this buddy already. */
     528               
     529                strncpy( newnick, nick, MAX_NICK_LENGTH );
     530                newnick[MAX_NICK_LENGTH] = 0;
     531               
     532                /* Some processing to make sure this string is a valid IRC nickname. */
     533                nick_strip( newnick );
     534                if( set_getbool( &ic->irc->set, "lcnicks" ) )
     535                        nick_lc( newnick );
     536               
     537                if( strcmp( u->nick, newnick ) != 0 )
     538                {
     539                        /* Only do this if newnick is different from the current one.
     540                           If rejoining a channel, maybe we got this nick already
     541                           (and dedupe would only add an underscore. */
     542                        nick_dedupe( ic->acc, handle, newnick );
     543                       
     544                        /* u->nick will be freed halfway the process, so it can't be
     545                           passed as an argument. */
     546                        orig_nick = g_strdup( u->nick );
     547                        user_rename( ic->irc, orig_nick, newnick );
     548                        g_free( orig_nick );
     549                }
     550        }
    427551}
    428552
     
    469593        data->ic = ic;
    470594        data->handle = g_strdup( handle );
    471         query_add( (irc_t *) ic->bee->ui_data, ic, s,
    472                    imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
     595        query_add( ic->irc, ic, s, imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
    473596}
    474597
     
    495618       
    496619        /* TODO: Make a setting for this! */
    497         if( bee_user_by_handle( ic->bee, ic, handle ) != NULL )
     620        if( user_findhandle( ic, handle ) != NULL )
    498621                return;
    499622       
     
    502625        data->ic = ic;
    503626        data->handle = g_strdup( handle );
    504         query_add( (irc_t *) ic->bee->ui_data, ic, s,
    505                    imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
    506 }
    507 
    508 struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle )
    509 {
    510         return bee_user_by_handle( ic->bee, ic, handle );
     627        query_add( ic->irc, ic, s, imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
     628}
     629
     630
     631/* server.c */                   
     632
     633void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message )
     634{
     635        user_t *u;
     636        int oa, oo;
     637       
     638        u = user_findhandle( ic, (char*) handle );
     639       
     640        if( !u )
     641        {
     642                if( g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "add" ) == 0 )
     643                {
     644                        imcb_add_buddy( ic, (char*) handle, NULL );
     645                        u = user_findhandle( ic, (char*) handle );
     646                }
     647                else
     648                {
     649                        if( set_getbool( &ic->irc->set, "debug" ) || g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "ignore" ) != 0 )
     650                        {
     651                                imcb_log( ic, "imcb_buddy_status() for unknown handle %s:", handle );
     652                                imcb_log( ic, "flags = %d, state = %s, message = %s", flags,
     653                                          state ? state : "NULL", message ? message : "NULL" );
     654                        }
     655                       
     656                        return;
     657                }
     658        }
     659       
     660        oa = u->away != NULL;
     661        oo = u->online;
     662       
     663        g_free( u->away );
     664        g_free( u->status_msg );
     665        u->away = u->status_msg = NULL;
     666       
     667        if( set_getbool( &ic->irc->set, "show_offline" ) && !u->online )
     668        {
     669                /* always set users as online */
     670                irc_spawn( ic->irc, u );
     671                u->online = 1;
     672                if( !( flags & OPT_LOGGED_IN ) )
     673                {
     674                        /* set away message if user isn't really online */
     675                        u->away = g_strdup( "User is offline" );
     676                }
     677        }
     678        else if( ( flags & OPT_LOGGED_IN ) && !u->online )
     679        {
     680                irc_spawn( ic->irc, u );
     681                u->online = 1;
     682        }
     683        else if( !( flags & OPT_LOGGED_IN ) && u->online )
     684        {
     685                struct groupchat *c;
     686               
     687                if( set_getbool( &ic->irc->set, "show_offline" ) )
     688                {
     689                        /* keep offline users in channel and set away message to "offline" */
     690                        u->away = g_strdup( "User is offline" );
     691
     692                        /* Keep showing him/her in the control channel but not in groupchats. */
     693                        for( c = ic->groupchats; c; c = c->next )
     694                        {
     695                                if( remove_chat_buddy_silent( c, handle ) && c->joined )
     696                                        irc_part( c->ic->irc, u, c->channel );
     697                        }
     698                }
     699                else
     700                {
     701                        /* kill offline users */
     702                        irc_kill( ic->irc, u );
     703                        u->online = 0;
     704
     705                        /* Remove him/her from the groupchats to prevent PART messages after he/she QUIT already */
     706                        for( c = ic->groupchats; c; c = c->next )
     707                                remove_chat_buddy_silent( c, handle );
     708                }
     709        }
     710
     711        if( flags & OPT_AWAY )
     712        {
     713                if( state && message )
     714                {
     715                        u->away = g_strdup_printf( "%s (%s)", state, message );
     716                }
     717                else if( state )
     718                {
     719                        u->away = g_strdup( state );
     720                }
     721                else if( message )
     722                {
     723                        u->away = g_strdup( message );
     724                }
     725                else
     726                {
     727                        u->away = g_strdup( "Away" );
     728                }
     729        }
     730        else
     731        {
     732                u->status_msg = g_strdup( message );
     733        }
     734       
     735        /* early if-clause for show_offline even if there is some redundant code here because this isn't LISP but C ;) */
     736        if( set_getbool( &ic->irc->set, "show_offline" ) && set_getbool( &ic->irc->set, "away_devoice" ) )
     737        {
     738                char *from;
     739               
     740                if( set_getbool( &ic->irc->set, "simulate_netsplit" ) )
     741                {
     742                        from = g_strdup( ic->irc->myhost );
     743                }
     744                else
     745                {
     746                        from = g_strdup_printf( "%s!%s@%s", ic->irc->mynick, ic->irc->mynick,
     747                                                            ic->irc->myhost );
     748                }
     749
     750                /* if we use show_offline, we op online users, voice away users, and devoice/deop offline users */
     751                if( flags & OPT_LOGGED_IN )
     752                {
     753                        /* user is "online" (either really online or away) */
     754                        irc_write( ic->irc, ":%s MODE %s %cv%co %s %s", from, ic->irc->channel,
     755                                                                  u->away?'+':'-', u->away?'-':'+', u->nick, u->nick );
     756                }
     757                else
     758                {
     759                        /* user is offline */
     760                        irc_write( ic->irc, ":%s MODE %s -vo %s %s", from, ic->irc->channel, u->nick, u->nick );
     761                }
     762        }
     763        else
     764        {
     765                /* LISPy... */
     766                if( ( set_getbool( &ic->irc->set, "away_devoice" ) ) &&         /* Don't do a thing when user doesn't want it */
     767                    ( u->online ) &&                                            /* Don't touch offline people */
     768                    ( ( ( u->online != oo ) && !u->away ) ||                    /* Voice joining people */
     769                      ( ( u->online == oo ) && ( oa == !u->away ) ) ) )         /* (De)voice people changing state */
     770                {
     771                        char *from;
     772
     773                        if( set_getbool( &ic->irc->set, "simulate_netsplit" ) )
     774                        {
     775                                from = g_strdup( ic->irc->myhost );
     776                        }
     777                        else
     778                        {
     779                                from = g_strdup_printf( "%s!%s@%s", ic->irc->mynick, ic->irc->mynick,
     780                                                                    ic->irc->myhost );
     781                        }
     782                        irc_write( ic->irc, ":%s MODE %s %cv %s", from, ic->irc->channel,
     783                                                                  u->away?'-':'+', u->nick );
     784                        g_free( from );
     785                }
     786        }
     787}
     788
     789void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at )
     790{
     791        irc_t *irc = ic->irc;
     792        char *wrapped, *ts = NULL;
     793        user_t *u;
     794       
     795        u = user_findhandle( ic, handle );
     796       
     797        if( !u )
     798        {
     799                char *h = set_getstr( &irc->set, "handle_unknown" );
     800               
     801                if( g_strcasecmp( h, "ignore" ) == 0 )
     802                {
     803                        if( set_getbool( &irc->set, "debug" ) )
     804                                imcb_log( ic, "Ignoring message from unknown handle %s", handle );
     805                       
     806                        return;
     807                }
     808                else if( g_strncasecmp( h, "add", 3 ) == 0 )
     809                {
     810                        int private = set_getbool( &irc->set, "private" );
     811                       
     812                        if( h[3] )
     813                        {
     814                                if( g_strcasecmp( h + 3, "_private" ) == 0 )
     815                                        private = 1;
     816                                else if( g_strcasecmp( h + 3, "_channel" ) == 0 )
     817                                        private = 0;
     818                        }
     819                       
     820                        imcb_add_buddy( ic, handle, NULL );
     821                        u = user_findhandle( ic, handle );
     822                        u->is_private = private;
     823                }
     824                else
     825                {
     826                        imcb_log( ic, "Message from unknown handle %s:", handle );
     827                        u = user_find( irc, irc->mynick );
     828                }
     829        }
     830       
     831        if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
     832            ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
     833                strip_html( msg );
     834       
     835        if( set_getbool( &ic->irc->set, "display_timestamps" ) &&
     836            ( ts = format_timestamp( irc, sent_at ) ) )
     837        {
     838                char *new = g_strconcat( ts, msg, NULL );
     839                g_free( ts );
     840                ts = msg = new;
     841        }
     842       
     843        wrapped = word_wrap( msg, 425 );
     844        irc_msgfrom( irc, u->nick, wrapped );
     845        g_free( wrapped );
     846        g_free( ts );
     847}
     848
     849void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags )
     850{
     851        user_t *u;
     852       
     853        if( !set_getbool( &ic->irc->set, "typing_notice" ) )
     854                return;
     855       
     856        if( ( u = user_findhandle( ic, handle ) ) )
     857        {
     858                char buf[256];
     859               
     860                g_snprintf( buf, 256, "\1TYPING %d\1", ( flags >> 8 ) & 3 );
     861                irc_privmsg( ic->irc, u, "PRIVMSG", ic->irc->nick, NULL, buf );
     862        }
     863}
     864
     865struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle )
     866{
     867        struct groupchat *c;
     868       
     869        /* This one just creates the conversation structure, user won't see anything yet */
     870       
     871        if( ic->groupchats )
     872        {
     873                for( c = ic->groupchats; c->next; c = c->next );
     874                c = c->next = g_new0( struct groupchat, 1 );
     875        }
     876        else
     877                ic->groupchats = c = g_new0( struct groupchat, 1 );
     878       
     879        c->ic = ic;
     880        c->title = g_strdup( handle );
     881        c->channel = g_strdup_printf( "&chat_%03d", ic->irc->c_id++ );
     882        c->topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title );
     883       
     884        if( set_getbool( &ic->irc->set, "debug" ) )
     885                imcb_log( ic, "Creating new conversation: (id=%p,handle=%s)", c, handle );
     886       
     887        return c;
     888}
     889
     890void imcb_chat_name_hint( struct groupchat *c, const char *name )
     891{
     892        if( !c->joined )
     893        {
     894                struct im_connection *ic = c->ic;
     895                char stripped[MAX_NICK_LENGTH+1], *full_name;
     896               
     897                strncpy( stripped, name, MAX_NICK_LENGTH );
     898                stripped[MAX_NICK_LENGTH] = '\0';
     899                nick_strip( stripped );
     900                if( set_getbool( &ic->irc->set, "lcnicks" ) )
     901                        nick_lc( stripped );
     902               
     903                full_name = g_strdup_printf( "&%s", stripped );
     904               
     905                if( stripped[0] &&
     906                    nick_cmp( stripped, ic->irc->channel + 1 ) != 0 &&
     907                    irc_chat_by_channel( ic->irc, full_name ) == NULL )
     908                {
     909                        g_free( c->channel );
     910                        c->channel = full_name;
     911                }
     912                else
     913                {
     914                        g_free( full_name );
     915                }
     916        }
     917}
     918
     919void imcb_chat_free( struct groupchat *c )
     920{
     921        struct im_connection *ic = c->ic;
     922        struct groupchat *l;
     923        GList *ir;
     924       
     925        if( set_getbool( &ic->irc->set, "debug" ) )
     926                imcb_log( ic, "You were removed from conversation %p", c );
     927       
     928        if( c )
     929        {
     930                if( c->joined )
     931                {
     932                        user_t *u, *r;
     933                       
     934                        r = user_find( ic->irc, ic->irc->mynick );
     935                        irc_privmsg( ic->irc, r, "PRIVMSG", c->channel, "", "Cleaning up channel, bye!" );
     936                       
     937                        u = user_find( ic->irc, ic->irc->nick );
     938                        irc_kick( ic->irc, u, c->channel, r );
     939                        /* irc_part( ic->irc, u, c->channel ); */
     940                }
     941               
     942                /* Find the previous chat in the linked list. */
     943                for( l = ic->groupchats; l && l->next != c; l = l->next );
     944               
     945                if( l )
     946                        l->next = c->next;
     947                else
     948                        ic->groupchats = c->next;
     949               
     950                for( ir = c->in_room; ir; ir = ir->next )
     951                        g_free( ir->data );
     952                g_list_free( c->in_room );
     953                g_free( c->channel );
     954                g_free( c->title );
     955                g_free( c->topic );
     956                g_free( c );
     957        }
     958}
     959
     960void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at )
     961{
     962        struct im_connection *ic = c->ic;
     963        char *wrapped;
     964        user_t *u;
     965       
     966        /* Gaim sends own messages through this too. IRC doesn't want this, so kill them */
     967        if( g_strcasecmp( who, ic->acc->user ) == 0 )
     968                return;
     969       
     970        u = user_findhandle( ic, who );
     971       
     972        if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
     973            ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
     974                strip_html( msg );
     975       
     976        wrapped = word_wrap( msg, 425 );
     977        if( c && u )
     978        {
     979                char *ts = NULL;
     980                if( set_getbool( &ic->irc->set, "display_timestamps" ) )
     981                        ts = format_timestamp( ic->irc, sent_at );
     982                irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, ts ? : "", wrapped );
     983                g_free( ts );
     984        }
     985        else
     986        {
     987                imcb_log( ic, "Message from/to conversation %s@%p (unknown conv/user): %s", who, c, wrapped );
     988        }
     989        g_free( wrapped );
     990}
     991
     992void imcb_chat_log( struct groupchat *c, char *format, ... )
     993{
     994        irc_t *irc = c->ic->irc;
     995        va_list params;
     996        char *text;
     997        user_t *u;
     998       
     999        va_start( params, format );
     1000        text = g_strdup_vprintf( format, params );
     1001        va_end( params );
     1002       
     1003        u = user_find( irc, irc->mynick );
     1004       
     1005        irc_privmsg( irc, u, "PRIVMSG", c->channel, "System message: ", text );
     1006       
     1007        g_free( text );
     1008}
     1009
     1010void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at )
     1011{
     1012        struct im_connection *ic = c->ic;
     1013        user_t *u = NULL;
     1014       
     1015        if( who == NULL)
     1016                u = user_find( ic->irc, ic->irc->mynick );
     1017        else if( g_strcasecmp( who, ic->acc->user ) == 0 )
     1018                u = user_find( ic->irc, ic->irc->nick );
     1019        else
     1020                u = user_findhandle( ic, who );
     1021       
     1022        if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
     1023            ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
     1024                strip_html( topic );
     1025       
     1026        g_free( c->topic );
     1027        c->topic = g_strdup( topic );
     1028       
     1029        if( c->joined && u )
     1030                irc_write( ic->irc, ":%s!%s@%s TOPIC %s :%s", u->nick, u->user, u->host, c->channel, topic );
     1031}
     1032
     1033
     1034/* buddy_chat.c */
     1035
     1036void imcb_chat_add_buddy( struct groupchat *b, const char *handle )
     1037{
     1038        user_t *u = user_findhandle( b->ic, handle );
     1039        int me = 0;
     1040       
     1041        if( set_getbool( &b->ic->irc->set, "debug" ) )
     1042                imcb_log( b->ic, "User %s added to conversation %p", handle, b );
     1043       
     1044        /* It might be yourself! */
     1045        if( b->ic->acc->prpl->handle_cmp( handle, b->ic->acc->user ) == 0 )
     1046        {
     1047                u = user_find( b->ic->irc, b->ic->irc->nick );
     1048                if( !b->joined )
     1049                        irc_join( b->ic->irc, u, b->channel );
     1050                b->joined = me = 1;
     1051        }
     1052       
     1053        /* Most protocols allow people to join, even when they're not in
     1054           your contact list. Try to handle that here */
     1055        if( !u )
     1056        {
     1057                imcb_add_buddy( b->ic, handle, NULL );
     1058                u = user_findhandle( b->ic, handle );
     1059        }
     1060       
     1061        /* Add the handle to the room userlist, if it's not 'me' */
     1062        if( !me )
     1063        {
     1064                if( b->joined )
     1065                        irc_join( b->ic->irc, u, b->channel );
     1066                b->in_room = g_list_append( b->in_room, g_strdup( handle ) );
     1067        }
     1068}
     1069
     1070/* This function is one BIG hack... :-( EREWRITE */
     1071void imcb_chat_remove_buddy( struct groupchat *b, const char *handle, const char *reason )
     1072{
     1073        user_t *u;
     1074        int me = 0;
     1075       
     1076        if( set_getbool( &b->ic->irc->set, "debug" ) )
     1077                imcb_log( b->ic, "User %s removed from conversation %p (%s)", handle, b, reason ? reason : "" );
     1078       
     1079        /* It might be yourself! */
     1080        if( g_strcasecmp( handle, b->ic->acc->user ) == 0 )
     1081        {
     1082                if( b->joined == 0 )
     1083                        return;
     1084               
     1085                u = user_find( b->ic->irc, b->ic->irc->nick );
     1086                b->joined = 0;
     1087                me = 1;
     1088        }
     1089        else
     1090        {
     1091                u = user_findhandle( b->ic, handle );
     1092        }
     1093       
     1094        if( me || ( remove_chat_buddy_silent( b, handle ) && b->joined && u ) )
     1095                irc_part( b->ic->irc, u, b->channel );
     1096}
     1097
     1098static int remove_chat_buddy_silent( struct groupchat *b, const char *handle )
     1099{
     1100        GList *i;
     1101       
     1102        /* Find the handle in the room userlist and shoot it */
     1103        i = b->in_room;
     1104        while( i )
     1105        {
     1106                if( g_strcasecmp( handle, i->data ) == 0 )
     1107                {
     1108                        g_free( i->data );
     1109                        b->in_room = g_list_remove( b->in_room, i->data );
     1110                        return( 1 );
     1111                }
     1112               
     1113                i = i->next;
     1114        }
     1115       
     1116        return( 0 );
     1117}
     1118
     1119
     1120/* Misc. BitlBee stuff which shouldn't really be here */
     1121
     1122char *set_eval_away_devoice( set_t *set, char *value )
     1123{
     1124        irc_t *irc = set->data;
     1125        int st;
     1126       
     1127        if( !is_bool( value ) )
     1128                return SET_INVALID;
     1129       
     1130        st = bool2int( value );
     1131       
     1132        /* Horror.... */
     1133       
     1134        if( st != set_getbool( &irc->set, "away_devoice" ) )
     1135        {
     1136                char list[80] = "";
     1137                user_t *u = irc->users;
     1138                int i = 0, count = 0;
     1139                char pm;
     1140                char v[80];
     1141               
     1142                if( st )
     1143                        pm = '+';
     1144                else
     1145                        pm = '-';
     1146               
     1147                while( u )
     1148                {
     1149                        if( u->ic && u->online && !u->away )
     1150                        {
     1151                                if( ( strlen( list ) + strlen( u->nick ) ) >= 79 )
     1152                                {
     1153                                        for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0;
     1154                                        irc_write( irc, ":%s MODE %s %c%s%s",
     1155                                                   irc->myhost,
     1156                                                   irc->channel, pm, v, list );
     1157                                       
     1158                                        *list = 0;
     1159                                        count = 0;
     1160                                }
     1161                               
     1162                                sprintf( list + strlen( list ), " %s", u->nick );
     1163                                count ++;
     1164                        }
     1165                        u = u->next;
     1166                }
     1167               
     1168                /* $v = 'v' x $i */
     1169                for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0;
     1170                irc_write( irc, ":%s MODE %s %c%s%s", irc->myhost,
     1171                                                            irc->channel, pm, v, list );
     1172        }
     1173       
     1174        return value;
     1175}
     1176
     1177char *set_eval_timezone( set_t *set, char *value )
     1178{
     1179        char *s;
     1180       
     1181        if( strcmp( value, "local" ) == 0 ||
     1182            strcmp( value, "gmt" ) == 0 || strcmp( value, "utc" ) == 0 )
     1183                return value;
     1184       
     1185        /* Otherwise: +/- at the beginning optional, then one or more numbers,
     1186           possibly followed by a colon and more numbers. Don't bother bound-
     1187           checking them since users are free to shoot themselves in the foot. */
     1188        s = value;
     1189        if( *s == '+' || *s == '-' )
     1190                s ++;
     1191       
     1192        /* \d+ */
     1193        if( !isdigit( *s ) )
     1194                return SET_INVALID;
     1195        while( *s && isdigit( *s ) ) s ++;
     1196       
     1197        /* EOS? */
     1198        if( *s == '\0' )
     1199                return value;
     1200       
     1201        /* Otherwise, colon */
     1202        if( *s != ':' )
     1203                return SET_INVALID;
     1204        s ++;
     1205       
     1206        /* \d+ */
     1207        if( !isdigit( *s ) )
     1208                return SET_INVALID;
     1209        while( *s && isdigit( *s ) ) s ++;
     1210       
     1211        /* EOS */
     1212        return *s == '\0' ? value : SET_INVALID;
     1213}
     1214
     1215static char *format_timestamp( irc_t *irc, time_t msg_ts )
     1216{
     1217        time_t now_ts = time( NULL );
     1218        struct tm now, msg;
     1219        char *set;
     1220       
     1221        /* If the timestamp is <= 0 or less than a minute ago, discard it as
     1222           it doesn't seem to add to much useful info and/or might be noise. */
     1223        if( msg_ts <= 0 || msg_ts > now_ts - 60 )
     1224                return NULL;
     1225       
     1226        set = set_getstr( &irc->set, "timezone" );
     1227        if( strcmp( set, "local" ) == 0 )
     1228        {
     1229                localtime_r( &now_ts, &now );
     1230                localtime_r( &msg_ts, &msg );
     1231        }
     1232        else
     1233        {
     1234                int hr, min = 0, sign = 60;
     1235               
     1236                if( set[0] == '-' )
     1237                {
     1238                        sign *= -1;
     1239                        set ++;
     1240                }
     1241                else if( set[0] == '+' )
     1242                {
     1243                        set ++;
     1244                }
     1245               
     1246                if( sscanf( set, "%d:%d", &hr, &min ) >= 1 )
     1247                {
     1248                        msg_ts += sign * ( hr * 60 + min );
     1249                        now_ts += sign * ( hr * 60 + min );
     1250                }
     1251               
     1252                gmtime_r( &now_ts, &now );
     1253                gmtime_r( &msg_ts, &msg );
     1254        }
     1255       
     1256        if( msg.tm_year == now.tm_year && msg.tm_yday == now.tm_yday )
     1257                return g_strdup_printf( "\x02[\x02\x02\x02%02d:%02d:%02d\x02]\x02 ",
     1258                                        msg.tm_hour, msg.tm_min, msg.tm_sec );
     1259        else
     1260                return g_strdup_printf( "\x02[\x02\x02\x02%04d-%02d-%02d "
     1261                                        "%02d:%02d:%02d\x02]\x02 ",
     1262                                        msg.tm_year + 1900, msg.tm_mon + 1, msg.tm_mday,
     1263                                        msg.tm_hour, msg.tm_min, msg.tm_sec );
    5111264}
    5121265
    5131266/* The plan is to not allow straight calls to prpl functions anymore, but do
    5141267   them all from some wrappers. We'll start to define some down here: */
     1268
     1269int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags )
     1270{
     1271        char *buf = NULL;
     1272        int st;
     1273       
     1274        if( ( ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
     1275        {
     1276                buf = escape_html( msg );
     1277                msg = buf;
     1278        }
     1279       
     1280        st = ic->acc->prpl->buddy_msg( ic, handle, msg, flags );
     1281        g_free( buf );
     1282       
     1283        return st;
     1284}
    5151285
    5161286int imc_chat_msg( struct groupchat *c, char *msg, int flags )
     
    5411311       
    5421312        away = set_getstr( &ic->acc->set, "away" ) ?
    543              : set_getstr( &ic->bee->set, "away" );
     1313             : set_getstr( &ic->irc->set, "away" );
    5441314        if( away && *away )
    5451315        {
     
    5521322                away = NULL;
    5531323                msg = set_getstr( &ic->acc->set, "status" ) ?
    554                     : set_getstr( &ic->bee->set, "status" );
     1324                    : set_getstr( &ic->irc->set, "status" );
    5551325        }
    5561326       
  • protocols/nogaim.h

    rf1cea66 r560d0a0  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2010 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    8787       
    8888        /* BitlBee */
    89         bee_t *bee;
    90        
    91         GSList *groupchats;
     89        irc_t *irc;
     90       
     91        struct groupchat *groupchats;
    9292};
    9393
     
    100100         * already, for example to avoid adding somebody two times. */
    101101        GList *in_room;
    102         //GList *ignored;
    103        
    104         //struct groupchat *next;
     102        GList *ignored;
     103       
     104        struct groupchat *next;
     105        char *channel;
    105106        /* The title variable contains the ID you gave when you created the
    106107         * chat using imcb_chat_new(). */
     
    113114         * structure for your protocol's needs. */
    114115        void *data;
    115         void *ui_data;
    116116};
    117117
     
    287287G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick );
    288288
     289/* Buddy activity */
     290/* To manipulate the status of a handle.
     291 * - flags can be |='d with OPT_* constants. You will need at least:
     292 *   OPT_LOGGED_IN and OPT_AWAY.
     293 * - 'state' and 'message' can be NULL */
     294G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message );
     295/* Not implemented yet! */ G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle );
     296/* Call when a handle says something. 'flags' and 'sent_at may be just 0. */
     297G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at );
    289298G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags );
    290 G_MODULE_EXPORT struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle );
    291299G_MODULE_EXPORT void imcb_clean_handle( struct im_connection *ic, char *handle );
    292300
     
    314322/* Actions, or whatever. */
    315323int imc_away_send_update( struct im_connection *ic );
     324int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags );
    316325int imc_chat_msg( struct groupchat *c, char *msg, int flags );
    317326
  • protocols/oscar/oscar.c

    rf1cea66 r560d0a0  
    254254
    255255        u = t = g_strdup(s);
     256
     257        strcpy(t, s);
    256258        g_strdown(t);
    257259
     
    650652        struct im_connection *ic = sess->aux_data;
    651653        struct chat_connection *chatcon;
    652         struct groupchat *c = NULL;
    653654        static int id = 1;
    654655
     
    663664        chatcon = find_oscar_chat_by_conn(ic, fr->conn);
    664665        chatcon->id = id;
    665        
    666         c = bee_chat_by_title(ic->bee, ic, chatcon->show);
    667         if (c && !c->data)
    668                 chatcon->cnv = c;
    669         else
    670                 chatcon->cnv = imcb_chat_new(ic, chatcon->show);
     666        chatcon->cnv = imcb_chat_new(ic, chatcon->show);
    671667        chatcon->cnv->data = chatcon;
    672668
     
    938934        tmp = normalize(info->sn);
    939935        imcb_buddy_status(ic, tmp, flags, state_string, NULL);
    940         imcb_buddy_times(ic, tmp, signon, time_idle);
     936        /* imcb_buddy_times(ic, tmp, signon, time_idle); */
    941937
    942938
     
    10641060        aim_ssi_auth_reply(od->sess, od->conn, uin, 1, "");
    10651061        // aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHGRANTED, &message);
    1066         imcb_ask_add(data->ic, uin, NULL);
     1062        if(imcb_find_buddy(data->ic, uin) == NULL)
     1063                imcb_ask_add(data->ic, uin, NULL);
    10671064       
    10681065        g_free(uin);
     
    18251822        struct oscar_data *odata = (struct oscar_data *)g->proto_data;
    18261823        if (odata->icq) {
    1827                 /** FIXME(wilmer): Hmm, lost the ability to get away msgs here, do we care to get that back?
    18281824                struct buddy *budlight = imcb_find_buddy(g, who);
    18291825                if (budlight)
     
    18311827                                if (budlight->caps & AIM_CAPS_ICQSERVERRELAY)
    18321828                                        aim_send_im_ch2_geticqmessage(odata->sess, who, (budlight->uc & 0xff80) >> 7);
    1833                 */
    18341829        } else
    18351830                aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_AWAYMESSAGE);
     
    19581953static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {
    19591954        struct im_connection *ic = sess->aux_data;
    1960         struct aim_ssi_item *curitem, *curgroup;
     1955        struct aim_ssi_item *curitem;
    19611956        int tmp;
    19621957        char *nrm;
     
    19691964                switch (curitem->type) {
    19701965                        case 0x0000: /* Buddy */
    1971                                 if ((curitem->name) && (!imcb_buddy_by_handle(ic, nrm))) {
     1966                                if ((curitem->name) && (!imcb_find_buddy(ic, nrm))) {
    19721967                                        char *realname = NULL;
    19731968
    19741969                                        if (curitem->data && aim_gettlv(curitem->data, 0x0131, 1))
    19751970                                                    realname = aim_gettlv_str(curitem->data, 0x0131, 1);
    1976                                        
    1977                                         imcb_add_buddy(ic, nrm, curgroup->gid == curitem->gid ? curgroup->name : NULL);
     1971                                               
     1972                                        imcb_add_buddy(ic, nrm, NULL);
    19781973                                       
    19791974                                        if (realname) {
     
    19831978                                        }
    19841979                                }
    1985                                 break;
    1986 
    1987                         case 0x0001: /* Group */
    1988                                 curgroup = curitem;
    19891980                                break;
    19901981
     
    25292520        static int chat_id = 0;
    25302521        char * chatname;
    2531         struct groupchat *c;
    25322522       
    25332523        chatname = g_strdup_printf("%s%s_%d", isdigit(*ic->acc->user) ? "icq_" : "",
    25342524                                   ic->acc->user, chat_id++);
    2535        
    2536         c = imcb_chat_new(ic, chatname);
     2525 
    25372526        ret = oscar_chat_join(ic, chatname, NULL, NULL);
     2527
    25382528        aim_chat_invite(od->sess, od->conn, who, "", 4, chatname, 0x0);
    25392529
  • protocols/purple/ft.c

    rf1cea66 r560d0a0  
    7575                px->fn = mktemp( g_strdup( "/tmp/bitlbee-purple-ft.XXXXXX" ) );
    7676                px->fd = -1;
    77                 px->ic = purple_ic_by_pa( xfer->account );
    7877               
    7978                purple_xfer_set_local_filename( xfer, px->fn );
     
    144143                {
    145144                        purple_xfer_cancel_local( px->xfer );
    146                         imcb_file_canceled( px->ic, ft, "Read error" );
     145                        imcb_file_canceled( ft, "Read error" );
    147146                }
    148147        }
     
    151150        {
    152151                /*purple_xfer_end( px->xfer );*/
    153                 imcb_file_finished( px->ic, ft );
     152                imcb_file_finished( ft );
    154153        }
    155154       
     
    231230       
    232231        if( px->ft )
    233                 imcb_file_canceled( px->ic, px->ft, "Canceled by remote end" );
     232                imcb_file_canceled( px->ft, "Canceled by remote end" );
    234233        else
    235234                /* px->ft == NULL for sends, because of the two stages. :-/ */
     
    302301{
    303302        file_transfer_t *ft = data;
    304         struct prpl_xfer_data *px = ft->data;
    305303       
    306304        if( ft->write == NULL )
    307305        {
    308306                ft->write = prpl_xfer_write;
    309                 imcb_file_recv_start( px->ic, ft );
     307                imcb_file_recv_start( ft );
    310308        }
    311309       
     
    321319        if( write( px->fd, buffer, len ) != len )
    322320        {
    323                 imcb_file_canceled( px->ic, ft, "Error while writing temporary file" );
     321                imcb_file_canceled( ft, "Error while writing temporary file" );
    324322                return FALSE;
    325323        }
     
    331329               
    332330                purple_transfer_forward( ft );
    333                 imcb_file_finished( px->ic, ft );
     331                imcb_file_finished( ft );
    334332                px->ft = NULL;
    335333        }
  • protocols/purple/purple.c

    rf1cea66 r560d0a0  
    3535   any context so this is the only way to get that. Don't want to support
    3636   libpurple in daemon mode anyway. */
    37 static bee_t *local_bee;
     37static irc_t *local_irc;
    3838
    3939static char *set_eval_display_name( set_t *set, char *value );
     
    157157                       
    158158                default:
    159                         /** No way to talk to the user right now, invent one when
    160                         this becomes important.
    161159                        irc_usermsg( acc->irc, "Setting with unknown type: %s (%d) Expect stuff to break..\n",
    162160                                     name, purple_account_option_get_type( o ) );
    163                         */
    164161                        name = NULL;
    165162                }
     
    254251        PurpleAccount *pa;
    255252       
    256         if( local_bee != NULL && local_bee != acc->bee )
    257         {
    258                 imcb_error( ic,  "Daemon mode detected. Do *not* try to use libpurple in daemon mode! "
    259                                  "Please use inetd or ForkDaemon mode instead." );
    260                 imc_logout( ic, FALSE );
     253        if( local_irc != NULL && local_irc != acc->irc )
     254        {
     255                irc_usermsg( acc->irc, "Daemon mode detected. Do *not* try to use libpurple in daemon mode! "
     256                                       "Please use inetd or ForkDaemon mode instead." );
    261257                return;
    262258        }
    263         local_bee = acc->bee;
     259        local_irc = acc->irc;
    264260       
    265261        /* For now this is needed in the _connected() handlers if using
     
    687683                imcb_buddy_status( ic, bud->name, flags, purple_status_get_name( as ),
    688684                                   purple_status_get_attr_string( as, "message" ) );
    689                
    690                 imcb_buddy_times( ic, bud->name,
    691                                   purple_presence_get_login_time( bud->presence ),
    692                                   purple_presence_get_idle_time( bud->presence ) );
    693685        }
    694686}
     
    874866        pqad->user_data = user_data;
    875867       
    876         /* TODO: IRC stuff here :-( */
    877868        q = g_strdup_printf( "Request: %s\n\n%s\n\n%s", title, primary, secondary );
    878         pqad->bee_data = query_add( local_bee->ui_data, purple_ic_by_pa( account ), q,
     869        pqad->bee_data = query_add( local_irc, purple_ic_by_pa( account ), q,
    879870                prplcb_request_action_yes, prplcb_request_action_no, pqad );
    880871       
  • protocols/twitter/twitter_lib.c

    rf1cea66 r560d0a0  
    103103
    104104        // Check if the buddy is allready in the buddy list.
    105         if (!bee_user_by_handle( ic->bee, ic, name ))
     105        if (!imcb_find_buddy( ic, name ))
    106106        {
    107107                char *mode = set_getstr(&ic->acc->set, "mode");
  • protocols/yahoo/yahoo.c

    rf1cea66 r560d0a0  
    158158       
    159159        while( ic->groupchats )
    160                 imcb_chat_free( ic->groupchats->data );
     160                imcb_chat_free( ic->groupchats );
    161161       
    162162        for( l = yd->buddygroups; l; l = l->next )
     
    613613        imcb_buddy_status( ic, who, flags, state_string, msg );
    614614       
     615        /* Not implemented yet...
    615616        if( stat == YAHOO_STATUS_IDLE )
    616                 imcb_buddy_times( ic, who, 0, idle );
     617                imcb_buddy_times( ic, who, 0, away );
     618        */
    617619}
    618620
     
    794796        struct byahoo_conf_invitation *inv = data;
    795797        struct groupchat *b;
    796         GSList *l;
    797        
    798         for( l = inv->ic->groupchats; l; l = l->next )
    799         {
    800                 b = l->data;
     798       
     799        for( b = inv->ic->groupchats; b; b = b->next )
    801800                if( b == inv->c )
    802801                        break;
    803         }
    804802       
    805803        if( b != NULL )
     
    867865{
    868866        struct im_connection *ic = byahoo_get_ic_by_id( id );
    869         struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
     867        struct groupchat *c;
     868       
     869        for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
    870870       
    871871        if( c )
     
    877877{
    878878        struct im_connection *ic = byahoo_get_ic_by_id( id );
    879         struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
     879        struct groupchat *c;
     880       
     881        for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
    880882       
    881883        if( c )
     
    887889        struct im_connection *ic = byahoo_get_ic_by_id( id );
    888890        char *m = byahoo_strip( msg );
    889         struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
     891        struct groupchat *c;
     892       
     893        for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
    890894       
    891895        if( c )
  • query.c

    rf1cea66 r560d0a0  
    6464        }
    6565       
    66         if( g_strcasecmp( set_getstr( &irc->b->set, "query_order" ), "lifo" ) == 0 || irc->queries == q )
     66        if( g_strcasecmp( set_getstr( &irc->set, "query_order" ), "lifo" ) == 0 || irc->queries == q )
    6767                query_display( irc, q );
    6868       
     
    179179        query_t *q;
    180180       
    181         if( g_strcasecmp( set_getstr( &irc->b->set, "query_order" ), "fifo" ) == 0 )
     181        if( g_strcasecmp( set_getstr( &irc->set, "query_order" ), "fifo" ) == 0 )
    182182                q = irc->queries;
    183183        else
  • root_commands.c

    rf1cea66 r560d0a0  
    3232#include <string.h>
    3333
    34 void root_command_string( irc_t *irc, char *command )
    35 {
    36         root_command( irc, split_command_parts( command ) );
     34void root_command_string( irc_t *irc, user_t *u, char *command, int flags )
     35{
     36        char *cmd[IRC_MAX_ARGS];
     37        char *s;
     38        int k;
     39        char q = 0;
     40       
     41        memset( cmd, 0, sizeof( cmd ) );
     42        cmd[0] = command;
     43        k = 1;
     44        for( s = command; *s && k < ( IRC_MAX_ARGS - 1 ); s ++ )
     45                if( *s == ' ' && !q )
     46                {
     47                        *s = 0;
     48                        while( *++s == ' ' );
     49                        if( *s == '"' || *s == '\'' )
     50                        {
     51                                q = *s;
     52                                s ++;
     53                        }
     54                        if( *s )
     55                        {
     56                                cmd[k++] = s;
     57                                s --;
     58                        }
     59                        else
     60                        {
     61                                break;
     62                        }
     63                }
     64                else if( *s == '\\' && ( ( !q && s[1] ) || ( q && q == s[1] ) ) )
     65                {
     66                        char *cpy;
     67                       
     68                        for( cpy = s; *cpy; cpy ++ )
     69                                cpy[0] = cpy[1];
     70                }
     71                else if( *s == q )
     72                {
     73                        q = *s = 0;
     74                }
     75        cmd[k] = NULL;
     76       
     77        root_command( irc, cmd );
    3778}
    3879
     
    5192void root_command( irc_t *irc, char *cmd[] )
    5293{       
    53         int i, len;
     94        int i;
    5495       
    5596        if( !cmd[0] )
    5697                return;
    5798       
    58         len = strlen( cmd[0] );
    5999        for( i = 0; commands[i].command; i++ )
    60                 if( g_strncasecmp( commands[i].command, cmd[0], len ) == 0 )
    61                 {
    62                         if( commands[i+1].command &&
    63                             g_strncasecmp( commands[i+1].command, cmd[0], len ) == 0 )
    64                                 /* Only match on the first letters if the match is unique. */
    65                                 break;
    66                        
     100                if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
     101                {
    67102                        MIN_ARGS( commands[i].required_parameters );
    68103                       
     
    105140static void cmd_identify( irc_t *irc, char **cmd )
    106141{
    107         storage_status_t status;
     142        storage_status_t status = storage_load( irc, cmd[1] );
    108143        char *account_on[] = { "account", "on", NULL };
    109         gboolean load = TRUE;
    110         char *password = cmd[1];
    111        
    112         if( irc->status & USTATUS_IDENTIFIED )
     144       
     145        if( strchr( irc->umode, 'R' ) != NULL )
    113146        {
    114147                irc_usermsg( irc, "You're already logged in." );
    115148                return;
    116149        }
    117        
    118         if( strncmp( cmd[1], "-no", 3 ) == 0 )
    119         {
    120                 load = FALSE;
    121                 password = cmd[2];
    122         }
    123         else if( strncmp( cmd[1], "-force", 6 ) == 0 )
    124         {
    125                 password = cmd[2];
    126         }
    127         else if( irc->b->accounts != NULL )
    128         {
    129                 irc_usermsg( irc,
    130                              "You're trying to identify yourself, but already have "
    131                              "at least one IM account set up. "
    132                              "Use \x02identify -noload\x02 or \x02identify -force\x02 "
    133                              "instead (see \x02help identify\x02)." );
    134                 return;
    135         }
    136        
    137         if( password == NULL )
    138         {
    139                 MIN_ARGS( 2 );
    140         }
    141        
    142         if( load )
    143                 status = storage_load( irc, password );
    144         else
    145                 status = storage_check_pass( irc->user->nick, password );
    146150       
    147151        switch (status) {
     
    153157                break;
    154158        case STORAGE_OK:
    155                 irc_usermsg( irc, "Password accepted%s",
    156                              load ? ", settings and accounts loaded" : "" );
    157                 irc_setpass( irc, password );
     159                irc_usermsg( irc, "Password accepted, settings and accounts loaded" );
     160                irc_setpass( irc, cmd[1] );
    158161                irc->status |= USTATUS_IDENTIFIED;
    159162                irc_umode_set( irc, "+R", 1 );
    160                 if( load && set_getbool( &irc->b->set, "auto_connect" ) )
     163                if( set_getbool( &irc->set, "auto_connect" ) )
    161164                        cmd_account( irc, account_on );
    162165                break;
     
    198201        storage_status_t status;
    199202       
    200         status = storage_remove (irc->user->nick, cmd[1]);
     203        status = storage_remove (irc->nick, cmd[1]);
    201204        switch (status) {
    202205        case STORAGE_NO_SUCH_USER:
     
    210213                irc->status &= ~USTATUS_IDENTIFIED;
    211214                irc_umode_set( irc, "-R", 1 );
    212                 irc_usermsg( irc, "Account `%s' removed", irc->user->nick );
     215                irc_usermsg( irc, "Account `%s' removed", irc->nick );
    213216                break;
    214217        default:
     
    218221}
    219222
    220 static void cmd_save( irc_t *irc, char **cmd )
    221 {
    222         if( ( irc->status & USTATUS_IDENTIFIED ) == 0 )
    223                 irc_usermsg( irc, "Please create an account first" );
    224         else if( storage_save( irc, NULL, TRUE ) == STORAGE_OK )
    225                 irc_usermsg( irc, "Configuration saved" );
    226         else
    227                 irc_usermsg( irc, "Configuration could not be saved!" );
     223struct cmd_account_del_data
     224{
     225        account_t *a;
     226        irc_t *irc;
     227};
     228
     229void cmd_account_del_yes( void *data )
     230{
     231        struct cmd_account_del_data *cad = data;
     232        account_t *a;
     233       
     234        for( a = cad->irc->accounts; a && a != cad->a; a = a->next );
     235       
     236        if( a == NULL )
     237        {
     238                irc_usermsg( cad->irc, "Account already deleted" );
     239        }
     240        else if( a->ic )
     241        {
     242                irc_usermsg( cad->irc, "Account is still logged in, can't delete" );
     243        }
     244        else
     245        {
     246                account_del( cad->irc, a );
     247                irc_usermsg( cad->irc, "Account deleted" );
     248        }
     249        g_free( data );
     250}
     251
     252void cmd_account_del_no( void *data )
     253{
     254        g_free( data );
    228255}
    229256
     
    258285                set_name = set_full;
    259286               
    260                 head = &irc->b->set;
     287                head = &irc->set;
    261288        }
    262289        else
     
    329356        account_t *a;
    330357       
    331         if( ( a = account_get( irc->b, id ) ) )
     358        if( ( a = account_get( irc, id ) ) )
    332359                return &a->set;
    333360        else
     
    377404                }
    378405
    379                 a = account_add( irc->b, prpl, cmd[3], cmd[4] );
     406                a = account_add( irc, prpl, cmd[3], cmd[4] );
    380407                if( cmd[5] )
    381408                {
     
    391418                MIN_ARGS( 2 );
    392419
    393                 if( !( a = account_get( irc->b, cmd[2] ) ) )
     420                if( !( a = account_get( irc, cmd[2] ) ) )
    394421                {
    395422                        irc_usermsg( irc, "Invalid account" );
     
    401428                else
    402429                {
    403                         account_del( irc->b, a );
    404                         irc_usermsg( irc, "Account deleted" );
     430                        struct cmd_account_del_data *cad;
     431                        char *msg;
     432                       
     433                        cad = g_malloc( sizeof( struct cmd_account_del_data ) );
     434                        cad->a = a;
     435                        cad->irc = irc;
     436                       
     437                        msg = g_strdup_printf( "If you remove this account (%s(%s)), BitlBee will "
     438                                               "also forget all your saved nicknames. If you want "
     439                                               "to change your username/password, use the `account "
     440                                               "set' command. Are you sure you want to delete this "
     441                                               "account?", a->prpl->name, a->user );
     442                        query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, cad );
     443                        g_free( msg );
    405444                }
    406445        }
     
    412451                        irc_usermsg( irc, "Account list:" );
    413452               
    414                 for( a = irc->b->accounts; a; a = a->next )
     453                for( a = irc->accounts; a; a = a->next )
    415454                {
    416455                        char *con;
     
    435474                if( cmd[2] )
    436475                {
    437                         if( ( a = account_get( irc->b, cmd[2] ) ) )
     476                        if( ( a = account_get( irc, cmd[2] ) ) )
    438477                        {
    439478                                if( a->ic )
     
    444483                                else
    445484                                {
    446                                         account_on( irc->b, a );
     485                                        account_on( irc, a );
    447486                                }
    448487                        }
     
    455494                else
    456495                {
    457                         if ( irc->b->accounts )
    458                         {
     496                        if ( irc->accounts ) {
    459497                                irc_usermsg( irc, "Trying to get all accounts connected..." );
    460498                       
    461                                 for( a = irc->b->accounts; a; a = a->next )
     499                                for( a = irc->accounts; a; a = a->next )
    462500                                        if( !a->ic && a->auto_connect )
    463                                                 account_on( irc->b, a );
     501                                                account_on( irc, a );
    464502                        }
    465503                        else
     
    475513                        irc_usermsg( irc, "Deactivating all active (re)connections..." );
    476514                       
    477                         for( a = irc->b->accounts; a; a = a->next )
     515                        for( a = irc->accounts; a; a = a->next )
    478516                        {
    479517                                if( a->ic )
    480                                         account_off( irc->b, a );
     518                                        account_off( irc, a );
    481519                                else if( a->reconnect )
    482520                                        cancel_auto_reconnect( a );
    483521                        }
    484522                }
    485                 else if( ( a = account_get( irc->b, cmd[2] ) ) )
     523                else if( ( a = account_get( irc, cmd[2] ) ) )
    486524                {
    487525                        if( a->ic )
    488526                        {
    489                                 account_off( irc->b, a );
     527                                account_off( irc, a );
    490528                        }
    491529                        else if( a->reconnect )
     
    515553        {
    516554                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "account", cmd[1] );
    517         }
    518 }
    519 
    520 static set_t **cmd_channel_set_findhead( irc_t *irc, char *id )
    521 {
    522         irc_channel_t *ic;
    523        
    524         if( ( ic = irc_channel_get( irc, id ) ) )
    525                 return &ic->set;
    526         else
    527                 return NULL;
    528 }
    529 
    530 static void cmd_channel( irc_t *irc, char **cmd )
    531 {
    532         if( g_strcasecmp( cmd[1], "set" ) == 0 )
    533         {
    534                 MIN_ARGS( 2 );
    535                
    536                 cmd_set_real( irc, cmd + 1, cmd_channel_set_findhead, NULL );
    537         }
    538         else if( g_strcasecmp( cmd[1], "list" ) == 0 )
    539         {
    540                 GSList *l;
    541                 int i = 0;
    542                
    543                 if( strchr( irc->umode, 'b' ) )
    544                         irc_usermsg( irc, "Channel list:" );
    545                
    546                 for( l = irc->channels; l; l = l->next )
    547                 {
    548                         irc_channel_t *ic = l->data;
    549                        
    550                         irc_usermsg( irc, "%2d. %s, %s channel%s", i, ic->name,
    551                                      set_getstr( &ic->set, "type" ),
    552                                      ic->flags & IRC_CHANNEL_JOINED ? " (joined)" : "" );
    553                        
    554                         i ++;
    555                 }
    556                 irc_usermsg( irc, "End of channel list" );
    557         }
    558         else if( g_strcasecmp( cmd[1], "del" ) == 0 )
    559         {
    560                 irc_channel_t *ic;
    561                
    562                 MIN_ARGS( 2 );
    563                
    564                 if( ( ic = irc_channel_get( irc, cmd[2] ) ) &&
    565                    !( ic->flags & IRC_CHANNEL_JOINED ) &&
    566                     ic != ic->irc->default_channel )
    567                 {
    568                         irc_usermsg( irc, "Channel %s deleted.", ic->name );
    569                         irc_channel_free( ic );
    570                 }
    571                 else
    572                         irc_usermsg( irc, "Couldn't remove channel (main channel %s or "
    573                                           "channels you're still in cannot be deleted).",
    574                                           ic->irc->default_channel->name );
    575         }
    576         else
    577         {
    578                 irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "channel", cmd[1] );
    579555        }
    580556}
     
    592568        }
    593569       
    594         if( !( a = account_get( irc->b, cmd[1] ) ) )
     570        if( !( a = account_get( irc, cmd[1] ) ) )
    595571        {
    596572                irc_usermsg( irc, "Invalid account" );
     
    610586                        return;
    611587                }
    612                 else if( irc_user_by_name( irc, cmd[3] ) )
     588                else if( user_find( irc, cmd[3] ) )
    613589                {
    614590                        irc_usermsg( irc, "The requested nick `%s' already exists", cmd[3] );
     
    624600                a->ic->acc->prpl->add_buddy( a->ic, cmd[2], NULL );
    625601        else
    626                 /* Only for add -tmp. For regular adds, this callback will
    627                    be called once the IM server confirms. */
    628                 bee_user_new( irc->b, a->ic, cmd[2], BEE_USER_LOCAL );
     602                /* Yeah, officially this is a call-*back*... So if we just
     603                   called add_buddy, we'll wait for the IM server to respond
     604                   before we do this. */
     605                imcb_add_buddy( a->ic, cmd[2], NULL );
    629606       
    630607        irc_usermsg( irc, "Adding `%s' to your contact list", cmd[2]  );
    631 }
    632 
    633 static void cmd_remove( irc_t *irc, char **cmd )
    634 {
    635         irc_user_t *iu;
    636         bee_user_t *bu;
    637         char *s;
    638        
    639         if( !( iu = irc_user_by_name( irc, cmd[1] ) ) || !( bu = iu->bu ) )
    640         {
    641                 irc_usermsg( irc, "Buddy `%s' not found", cmd[1] );
    642                 return;
    643         }
    644         s = g_strdup( bu->handle );
    645        
    646         bu->ic->acc->prpl->remove_buddy( bu->ic, bu->handle, NULL );
    647         nick_del( bu->ic->acc, bu->handle );
    648         //TODO(wilmer): bee_user_free() and/or let the IM mod do it? irc_user_free( irc, cmd[1] );
    649        
    650         irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
    651         g_free( s );
    652        
    653         return;
    654608}
    655609
     
    661615        if( !cmd[2] )
    662616        {
    663                 irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
    664                 if( !iu || !iu->bu )
     617                user_t *u = user_find( irc, cmd[1] );
     618                if( !u || !u->ic )
    665619                {
    666620                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    667621                        return;
    668622                }
    669                 ic = iu->bu->ic;
    670                 cmd[2] = iu->bu->handle;
    671         }
    672         else if( !( a = account_get( irc->b, cmd[1] ) ) )
     623                ic = u->ic;
     624                cmd[2] = u->handle;
     625        }
     626        else if( !( a = account_get( irc, cmd[1] ) ) )
    673627        {
    674628                irc_usermsg( irc, "Invalid account" );
     
    693647static void cmd_rename( irc_t *irc, char **cmd )
    694648{
    695         irc_user_t *iu;
    696        
    697         iu = irc_user_by_name( irc, cmd[1] );
    698        
    699         if( iu == NULL )
     649        user_t *u;
     650       
     651        if( g_strcasecmp( cmd[1], irc->nick ) == 0 )
     652        {
     653                irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] );
     654        }
     655        else if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
     656        {
     657                if( strchr( CTYPES, cmd[2][0] ) && nick_ok( cmd[2] + 1 ) )
     658                {
     659                        u = user_find( irc, irc->nick );
     660                       
     661                        irc_part( irc, u, irc->channel );
     662                        g_free( irc->channel );
     663                        irc->channel = g_strdup( cmd[2] );
     664                        irc_join( irc, u, irc->channel );
     665                       
     666                        if( strcmp( cmd[0], "set_rename" ) != 0 )
     667                                set_setstr( &irc->set, "control_channel", cmd[2] );
     668                }
     669        }
     670        else if( user_find( irc, cmd[2] ) && ( nick_cmp( cmd[1], cmd[2] ) != 0 ) )
     671        {
     672                irc_usermsg( irc, "Nick `%s' already exists", cmd[2] );
     673        }
     674        else if( !nick_ok( cmd[2] ) )
     675        {
     676                irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] );
     677        }
     678        else if( !( u = user_find( irc, cmd[1] ) ) )
    700679        {
    701680                irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    702681        }
    703         else if( iu == irc->user )
    704         {
    705                 irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] );
    706         }
    707         else if( !nick_ok( cmd[2] ) )
    708         {
    709                 irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] );
    710         }
    711         else if( irc_user_by_name( irc, cmd[2] ) )
    712         {
    713                 irc_usermsg( irc, "Nick `%s' already exists", cmd[2] );
    714         }
    715         else
    716         {
    717                 if( !irc_user_set_nick( iu, cmd[2] ) )
    718                 {
    719                         irc_usermsg( irc, "Error while changing nick" );
    720                         return;
    721                 }
    722                
    723                 if( iu == irc->root )
    724                 {
     682        else
     683        {
     684                user_rename( irc, cmd[1], cmd[2] );
     685                irc_write( irc, ":%s!%s@%s NICK %s", cmd[1], u->user, u->host, cmd[2] );
     686                if( g_strcasecmp( cmd[1], irc->mynick ) == 0 )
     687                {
     688                        g_free( irc->mynick );
     689                        irc->mynick = g_strdup( cmd[2] );
     690                       
    725691                        /* If we're called internally (user did "set root_nick"),
    726692                           let's not go O(INF). :-) */
    727693                        if( strcmp( cmd[0], "set_rename" ) != 0 )
    728                                 set_setstr( &irc->b->set, "root_nick", cmd[2] );
    729                 }
    730                 else if( iu->bu )
    731                 {
    732                         nick_set( iu->bu->ic->acc, iu->bu->handle, cmd[2] );
     694                                set_setstr( &irc->set, "root_nick", cmd[2] );
     695                }
     696                else if( u->send_handler == buddy_send_handler )
     697                {
     698                        nick_set( u->ic->acc, u->handle, cmd[2] );
    733699                }
    734700               
     
    741707        irc_t *irc = set->data;
    742708       
    743         if( strcmp( irc->root->nick, new_nick ) != 0 )
    744         {
    745                 char *cmd[] = { "set_rename", irc->root->nick, new_nick, NULL };
     709        if( strcmp( irc->mynick, new_nick ) != 0 )
     710        {
     711                char *cmd[] = { "set_rename", irc->mynick, new_nick, NULL };
    746712               
    747713                cmd_rename( irc, cmd );
    748714        }
    749715       
    750         return strcmp( irc->root->nick, new_nick ) == 0 ? new_nick : SET_INVALID;
     716        return strcmp( irc->mynick, new_nick ) == 0 ? new_nick : SET_INVALID;
     717}
     718
     719char *set_eval_control_channel( set_t *set, char *new_name )
     720{
     721        irc_t *irc = set->data;
     722       
     723        if( strcmp( irc->channel, new_name ) != 0 )
     724        {
     725                char *cmd[] = { "set_rename", irc->channel, new_name, NULL };
     726               
     727                cmd_rename( irc, cmd );
     728        }
     729       
     730        return strcmp( irc->channel, new_name ) == 0 ? new_name : SET_INVALID;
     731}
     732
     733static void cmd_remove( irc_t *irc, char **cmd )
     734{
     735        user_t *u;
     736        char *s;
     737       
     738        if( !( u = user_find( irc, cmd[1] ) ) || !u->ic )
     739        {
     740                irc_usermsg( irc, "Buddy `%s' not found", cmd[1] );
     741                return;
     742        }
     743        s = g_strdup( u->handle );
     744       
     745        u->ic->acc->prpl->remove_buddy( u->ic, u->handle, NULL );
     746        nick_del( u->ic->acc, u->handle );
     747        user_del( irc, cmd[1] );
     748       
     749        irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
     750        g_free( s );
     751       
     752        return;
    751753}
    752754
     
    756758        account_t *a;
    757759       
    758         if( !cmd[2] && ( a = account_get( irc->b, cmd[1] ) ) && a->ic )
     760        if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->ic )
    759761        {
    760762                char *format;
     
    769771                for( l = a->ic->deny; l; l = l->next )
    770772                {
    771                         bee_user_t *bu = bee_user_by_handle( irc->b, a->ic, l->data );
    772                         irc_user_t *iu = bu ? bu->ui_data : NULL;
    773                         irc_usermsg( irc, format, l->data, iu ? iu->nick : "(none)" );
     773                        user_t *u = user_findhandle( a->ic, l->data );
     774                        irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" );
    774775                }
    775776                irc_usermsg( irc, "End of list." );
     
    779780        else if( !cmd[2] )
    780781        {
    781                 irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
    782                 if( !iu || !iu->bu )
     782                user_t *u = user_find( irc, cmd[1] );
     783                if( !u || !u->ic )
    783784                {
    784785                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    785786                        return;
    786787                }
    787                 ic = iu->bu->ic;
    788                 cmd[2] = iu->bu->handle;
    789         }
    790         else if( !( a = account_get( irc->b, cmd[1] ) ) )
     788                ic = u->ic;
     789                cmd[2] = u->handle;
     790        }
     791        else if( !( a = account_get( irc, cmd[1] ) ) )
    791792        {
    792793                irc_usermsg( irc, "Invalid account" );
     
    816817        account_t *a;
    817818       
    818         if( !cmd[2] && ( a = account_get( irc->b, cmd[1] ) ) && a->ic )
     819        if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->ic )
    819820        {
    820821                char *format;
     
    829830                for( l = a->ic->permit; l; l = l->next )
    830831                {
    831                         bee_user_t *bu = bee_user_by_handle( irc->b, a->ic, l->data );
    832                         irc_user_t *iu = bu ? bu->ui_data : NULL;
    833                         irc_usermsg( irc, format, l->data, iu ? iu->nick : "(none)" );
     832                        user_t *u = user_findhandle( a->ic, l->data );
     833                        irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" );
    834834                }
    835835                irc_usermsg( irc, "End of list." );
     
    839839        else if( !cmd[2] )
    840840        {
    841                 irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
    842                 if( !iu || !iu->bu )
     841                user_t *u = user_find( irc, cmd[1] );
     842                if( !u || !u->ic )
    843843                {
    844844                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    845845                        return;
    846846                }
    847                 ic = iu->bu->ic;
    848                 cmd[2] = iu->bu->handle;
    849         }
    850         else if( !( a = account_get( irc->b, cmd[1] ) ) )
     847                ic = u->ic;
     848                cmd[2] = u->handle;
     849        }
     850        else if( !( a = account_get( irc, cmd[1] ) ) )
    851851        {
    852852                irc_usermsg( irc, "Invalid account" );
     
    915915}
    916916
     917static void cmd_save( irc_t *irc, char **cmd )
     918{
     919        if( ( irc->status & USTATUS_IDENTIFIED ) == 0 )
     920                irc_usermsg( irc, "Please create an account first" );
     921        else if( storage_save( irc, NULL, TRUE ) == STORAGE_OK )
     922                irc_usermsg( irc, "Configuration saved" );
     923        else
     924                irc_usermsg( irc, "Configuration could not be saved!" );
     925}
     926
    917927static void cmd_blist( irc_t *irc, char **cmd )
    918928{
    919929        int online = 0, away = 0, offline = 0;
    920         GSList *l;
     930        user_t *u;
    921931        char s[256];
    922932        char *format;
     
    939949                format = "%-16.16s  %-40.40s  %s";
    940950       
    941         irc_usermsg( irc, format, "Nick", "Handle/Account", "Status" );
    942        
    943         for( l = irc->users; l; l = l->next )
    944         {
    945                 irc_user_t *iu = l->data;
    946                 bee_user_t *bu = iu->bu;
    947                
    948                 if( !bu || ( bu->flags & ( BEE_USER_ONLINE | BEE_USER_AWAY ) ) != BEE_USER_ONLINE )
    949                         continue;
    950                
     951        irc_usermsg( irc, format, "Nick", "User/Host/Network", "Status" );
     952       
     953        for( u = irc->users; u; u = u->next ) if( u->ic && u->online && !u->away )
     954        {
    951955                if( online == 1 )
    952956                {
    953957                        char st[256] = "Online";
    954958                       
    955                         if( bu->status_msg )
    956                                 g_snprintf( st, sizeof( st ) - 1, "Online (%s)", bu->status_msg );
    957                        
    958                         g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
    959                         irc_usermsg( irc, format, iu->nick, s, st );
     959                        if( u->status_msg )
     960                                g_snprintf( st, sizeof( st ) - 1, "Online (%s)", u->status_msg );
     961                       
     962                        g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user );
     963                        irc_usermsg( irc, format, u->nick, s, st );
    960964                }
    961965               
     
    963967        }
    964968
    965         for( l = irc->users; l; l = l->next )
    966         {
    967                 irc_user_t *iu = l->data;
    968                 bee_user_t *bu = iu->bu;
    969                
    970                 if( !bu || !( bu->flags & BEE_USER_ONLINE ) || !( bu->flags & BEE_USER_AWAY ) )
    971                         continue;
    972                
     969        for( u = irc->users; u; u = u->next ) if( u->ic && u->online && u->away )
     970        {
    973971                if( away == 1 )
    974972                {
    975                         g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
    976                         irc_usermsg( irc, format, iu->nick, s, irc_user_get_away( iu ) );
     973                        g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user );
     974                        irc_usermsg( irc, format, u->nick, s, u->away );
    977975                }
    978976                n_away ++;
    979977        }
    980978       
    981         for( l = irc->users; l; l = l->next )
    982         {
    983                 irc_user_t *iu = l->data;
    984                 bee_user_t *bu = iu->bu;
    985                
    986                 if( !bu || bu->flags & BEE_USER_ONLINE )
    987                         continue;
    988                
     979        for( u = irc->users; u; u = u->next ) if( u->ic && !u->online )
     980        {
    989981                if( offline == 1 )
    990982                {
    991                         g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
    992                         irc_usermsg( irc, format, iu->nick, s, "Offline" );
     983                        g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user );
     984                        irc_usermsg( irc, format, u->nick, s, "Offline" );
    993985                }
    994986                n_offline ++;
     
    996988       
    997989        irc_usermsg( irc, "%d buddies (%d available, %d away, %d offline)", n_online + n_away + n_offline, n_online, n_away, n_offline );
     990}
     991
     992static void cmd_nick( irc_t *irc, char **cmd )
     993{
     994        account_t *a;
     995
     996        if( !cmd[1] || !( a = account_get( irc, cmd[1] ) ) )
     997        {
     998                irc_usermsg( irc, "Invalid account");
     999        }
     1000        else if( !( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) ) )
     1001        {
     1002                irc_usermsg( irc, "That account is not on-line" );
     1003        }
     1004        else if ( !cmd[2] )
     1005        {
     1006                irc_usermsg( irc, "Your name is `%s'" , a->ic->displayname ? a->ic->displayname : "NULL" );
     1007        }
     1008        else if ( !a->prpl->set_my_name )
     1009        {
     1010                irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
     1011        }
     1012        else
     1013        {
     1014                irc_usermsg( irc, "Setting your name to `%s'", cmd[2] );
     1015               
     1016                a->prpl->set_my_name( a->ic, cmd[2] );
     1017        }
    9981018}
    9991019
     
    10181038}
    10191039
     1040static void cmd_join_chat( irc_t *irc, char **cmd )
     1041{
     1042        irc_usermsg( irc, "This command is now obsolete. "
     1043                          "Please try the `chat' command instead." );
     1044}
     1045
     1046static set_t **cmd_chat_set_findhead( irc_t *irc, char *id )
     1047{
     1048        struct chat *c;
     1049       
     1050        if( ( c = chat_get( irc, id ) ) )
     1051                return &c->set;
     1052        else
     1053                return NULL;
     1054}
     1055
    10201056static void cmd_chat( irc_t *irc, char **cmd )
    10211057{
    10221058        account_t *acc;
     1059        struct chat *c;
    10231060       
    10241061        if( g_strcasecmp( cmd[1], "add" ) == 0 )
    10251062        {
    10261063                char *channel, *s;
    1027                 struct irc_channel *ic;
    10281064               
    10291065                MIN_ARGS( 3 );
    10301066               
    1031                 if( !( acc = account_get( irc->b, cmd[2] ) ) )
     1067                if( !( acc = account_get( irc, cmd[2] ) ) )
    10321068                {
    10331069                        irc_usermsg( irc, "Invalid account" );
    1034                         return;
    1035                 }
    1036                 else if( !acc->prpl->chat_join )
    1037                 {
    1038                         irc_usermsg( irc, "Named chatrooms not supported on that account." );
    10391070                        return;
    10401071                }
     
    10531084                if( strchr( CTYPES, channel[0] ) == NULL )
    10541085                {
    1055                         s = g_strdup_printf( "#%s", channel );
     1086                        s = g_strdup_printf( "%c%s", CTYPES[0], channel );
    10561087                        g_free( channel );
    10571088                        channel = s;
    10581089                }
    10591090               
    1060                 if( ( ic = irc_channel_new( irc, channel ) ) &&
    1061                     set_setstr( &ic->set, "chat_type", "room" ) &&
    1062                     set_setstr( &ic->set, "account", cmd[2] ) &&
    1063                     set_setstr( &ic->set, "room", cmd[3] ) )
    1064                 {
    1065                         irc_usermsg( irc, "Chatroom successfully added." );
    1066                 }
    1067                 else
    1068                 {
    1069                         if( ic )
    1070                                 irc_channel_free( ic );
    1071                        
     1091                if( ( c = chat_add( irc, acc, cmd[3], channel ) ) )
     1092                        irc_usermsg( irc, "Chatroom added successfully." );
     1093                else
    10721094                        irc_usermsg( irc, "Could not add chatroom." );
     1095               
     1096                g_free( channel );
     1097        }
     1098        else if( g_strcasecmp( cmd[1], "list" ) == 0 )
     1099        {
     1100                int i = 0;
     1101               
     1102                if( strchr( irc->umode, 'b' ) )
     1103                        irc_usermsg( irc, "Chatroom list:" );
     1104               
     1105                for( c = irc->chatrooms; c; c = c->next )
     1106                {
     1107                        irc_usermsg( irc, "%2d. %s(%s) %s, %s", i, c->acc->prpl->name,
     1108                                          c->acc->user, c->handle, c->channel );
     1109                       
     1110                        i ++;
     1111                }
     1112                irc_usermsg( irc, "End of chatroom list" );
     1113        }
     1114        else if( g_strcasecmp( cmd[1], "set" ) == 0 )
     1115        {
     1116                MIN_ARGS( 2 );
     1117               
     1118                cmd_set_real( irc, cmd + 1, cmd_chat_set_findhead, NULL );
     1119        }
     1120        else if( g_strcasecmp( cmd[1], "del" ) == 0 )
     1121        {
     1122                MIN_ARGS( 2 );
     1123               
     1124                if( ( c = chat_get( irc, cmd[2] ) ) )
     1125                {
     1126                        chat_del( irc, c );
     1127                }
     1128                else
     1129                {
     1130                        irc_usermsg( irc, "Could not remove chat." );
    10731131                }
    10741132        }
    10751133        else if( g_strcasecmp( cmd[1], "with" ) == 0 )
    10761134        {
    1077                 irc_user_t *iu;
     1135                user_t *u;
    10781136               
    10791137                MIN_ARGS( 2 );
    10801138               
    1081                 if( ( iu = irc_user_by_name( irc, cmd[2] ) ) &&
    1082                     iu->bu && iu->bu->ic->acc->prpl->chat_with )
    1083                 {
    1084                         if( !iu->bu->ic->acc->prpl->chat_with( iu->bu->ic, iu->bu->handle ) )
     1139                if( ( u = user_find( irc, cmd[2] ) ) && u->ic && u->ic->acc->prpl->chat_with )
     1140                {
     1141                        if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) )
    10851142                        {
    10861143                                irc_usermsg( irc, "(Possible) failure while trying to open "
    1087                                                   "a groupchat with %s.", iu->nick );
     1144                                                  "a groupchat with %s.", u->nick );
    10881145                        }
    10891146                }
     
    11471204                        {
    11481205                                irc_usermsg( irc, "Rejecting file transfer for %s", file->file_name );
    1149                                 imcb_file_canceled( file->ic, file, "Denied by user" );
     1206                                imcb_file_canceled( file, "Denied by user" );
    11501207                        }
    11511208                        break;
     
    11541211                        {
    11551212                                irc_usermsg( irc, "Canceling file transfer for %s", file->file_name );
    1156                                 imcb_file_canceled( file->ic, file, "Canceled by user" );
     1213                                imcb_file_canceled( file, "Canceled by user" );
    11571214                        }
    11581215                        break;
     
    11611218}
    11621219
    1163 /* IMPORTANT: Keep this list sorted! The short command logic needs that. */
    11641220const command_t commands[] = {
     1221        { "help",           0, cmd_help,           0 },
     1222        { "identify",       1, cmd_identify,       0 },
     1223        { "register",       1, cmd_register,       0 },
     1224        { "drop",           1, cmd_drop,           0 },
    11651225        { "account",        1, cmd_account,        0 },
    11661226        { "add",            2, cmd_add,            0 },
     1227        { "info",           1, cmd_info,           0 },
     1228        { "rename",         2, cmd_rename,         0 },
     1229        { "remove",         1, cmd_remove,         0 },
     1230        { "block",          1, cmd_block,          0 },
    11671231        { "allow",          1, cmd_allow,          0 },
    1168         { "blist",          0, cmd_blist,          0 },
    1169         { "block",          1, cmd_block,          0 },
    1170         { "channel",        1, cmd_channel,        0 },
    1171         { "chat",           1, cmd_chat,           0 },
    1172         { "drop",           1, cmd_drop,           0 },
    1173         { "ft",             0, cmd_transfer,       0 },
    1174         { "help",           0, cmd_help,           0 },
    1175         { "identify",       1, cmd_identify,       0 },
    1176         { "info",           1, cmd_info,           0 },
    1177         { "no",             0, cmd_yesno,          0 },
    1178         { "qlist",          0, cmd_qlist,          0 },
    1179         { "register",       1, cmd_register,       0 },
    1180         { "remove",         1, cmd_remove,         0 },
    1181         { "rename",         2, cmd_rename,         0 },
    11821232        { "save",           0, cmd_save,           0 },
    11831233        { "set",            0, cmd_set,            0 },
     1234        { "yes",            0, cmd_yesno,          0 },
     1235        { "no",             0, cmd_yesno,          0 },
     1236        { "blist",          0, cmd_blist,          0 },
     1237        { "nick",           1, cmd_nick,           0 },
     1238        { "qlist",          0, cmd_qlist,          0 },
     1239        { "join_chat",      2, cmd_join_chat,      0 },
     1240        { "chat",           1, cmd_chat,           0 },
    11841241        { "transfer",       0, cmd_transfer,       0 },
    1185         { "yes",            0, cmd_yesno,          0 },
    11861242        { NULL }
    11871243};
  • set.c

    rf1cea66 r560d0a0  
    6969        while( s )
    7070        {
    71                 if( g_strcasecmp( s->key, key ) == 0 ||
    72                     ( s->old_key && g_strcasecmp( s->old_key, key ) == 0 ) )
     71                if( g_strcasecmp( s->key, key ) == 0 )
    7372                        break;
    7473                s = s->next;
     
    177176               
    178177                g_free( s->key );
    179                 g_free( s->old_key );
    180                 g_free( s->value );
    181                 g_free( s->def );
     178                if( s->value ) g_free( s->value );
     179                if( s->def ) g_free( s->def );
    182180                g_free( s );
    183181        }
     
    242240}
    243241
    244 /*
    245242char *set_eval_ops( set_t *set, char *value )
    246243{
     
    264261        return value;
    265262}
    266 */
  • set.h

    rf1cea66 r560d0a0  
    5454       
    5555        char *key;
    56         char *old_key;  /* Previously known as; for smooth upgrades. */
    5756        char *value;
    5857        char *def;      /* Default value. If the set_setstr() function
  • storage_xml.c

    rf1cea66 r560d0a0  
    147147                                         arc_decode( pass_cr, pass_len, &password, xd->given_pass ) )
    148148                {
    149                         xd->current_account = account_add( irc->b, prpl, handle, password );
     149                        xd->current_account = account_add( irc, prpl, handle, password );
    150150                        if( server )
    151151                                set_setstr( &xd->current_account->set, "server", server );
     
    181181                                xd->current_set_head = &xd->current_account->set;
    182182                        else
    183                                 xd->current_set_head = &xd->irc->b->set;
     183                                xd->current_set_head = &xd->irc->set;
    184184                       
    185185                        xd->current_setting = g_strdup( setting );
     
    215215                if( xd->current_account && handle && channel )
    216216                {
    217                         //xd->current_chat = chat_add( xd->irc, xd->current_account, handle, channel );
     217                        xd->current_chat = chat_add( xd->irc, xd->current_account, handle, channel );
    218218                }
    219219                else
     
    353353static storage_status_t xml_load( irc_t *irc, const char *password )
    354354{
    355         return xml_load_real( irc, irc->user->nick, password, XML_PASS_UNKNOWN );
     355        return xml_load_real( irc, irc->nick, password, XML_PASS_UNKNOWN );
    356356}
    357357
     
    396396        md5_state_t md5_state;
    397397       
    398         path2 = g_strdup( irc->user->nick );
     398        path2 = g_strdup( irc->nick );
    399399        nick_lc( path2 );
    400400        g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, path2, ".xml" );
     
    422422        pass_buf = base64_encode( pass_md5, 21 );
    423423       
    424         if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->user->nick, pass_buf, XML_FORMAT_VERSION ) )
     424        if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) )
    425425                goto write_error;
    426426       
    427427        g_free( pass_buf );
    428428       
    429         for( set = irc->b->set; set; set = set->next )
     429        for( set = irc->set; set; set = set->next )
    430430                if( set->value )
    431431                        if( !xml_printf( fd, 1, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
    432432                                goto write_error;
    433433       
    434         for( acc = irc->b->accounts; acc; acc = acc->next )
     434        for( acc = irc->accounts; acc; acc = acc->next )
    435435        {
    436436                unsigned char *pass_cr;
     
    470470                        goto write_error;
    471471               
    472 #if 0
    473472                for( c = irc->chatrooms; c; c = c->next )
    474473                {
     
    489488                                goto write_error;
    490489                }
    491 #endif
    492490               
    493491                if( !xml_printf( fd, 1, "</account>\n" ) )
Note: See TracChangeset for help on using the changeset viewer.