Changes in / [560d0a0:f1cea66]


Ignore:
Files:
14 added
6 deleted
40 edited

Legend:

Unmodified
Added
Removed
  • Makefile

    r560d0a0 rf1cea66  
    1010
    1111# Program variables
    12 objects = 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
    13 headers = 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
     12objects = 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)
     13headers = 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
    1414subdirs = lib protocols
    1515
  • bitlbee.h

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

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

    r560d0a0 rf1cea66  
    2727yahoo=1
    2828twitter=1
     29twitter=1
    2930purple=0
    3031
     
    6869--oscar=0/1     Disable/enable Oscar part (ICQ, AIM)    $oscar
    6970--yahoo=0/1     Disable/enable Yahoo part               $yahoo
    70 --twitter=0/1 Disable/enable Twitter part               $twitter
     71--twitter=0/1   Disable/enable Twitter part             $twitter
    7172
    7273--purple=0/1    Disable/enable libpurple support        $purple
  • dcc.c

    r560d0a0 rf1cea66  
    6161unsigned int receivedchunks=0, receiveddata=0;
    6262
    63 static void dcc_finish( file_transfer_t *file );
    64 static void dcc_close( file_transfer_t *file );
     63void dcc_finish( file_transfer_t *file );
     64void 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, char *user_nick, struct sockaddr_storage *saddr );
    67 gboolean dccs_recv_start( file_transfer_t *ft );
     66int dccs_send_request( struct dcc_file_transfer *df, irc_user_t *iu, struct sockaddr_storage *saddr );
    6867gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond);
    6968gboolean dccs_recv_write_request( file_transfer_t *ft );
     
    7170gboolean dcc_abort( dcc_file_transfer_t *df, char *reason, ... );
    7271
    73 /* As defined in ft.h */
    74 file_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 */
    86 void 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 */
    95 gboolean imcb_file_recv_start( file_transfer_t *ft )
    96 {
    97         return dccs_recv_start( ft );
    98 }
    99 
    100 /* As defined in ft.h */
    101 void 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 
    111 dcc_file_transfer_t *dcc_alloc_transfer( char *file_name, size_t file_size, struct im_connection *ic )
     72dcc_file_transfer_t *dcc_alloc_transfer( const char *file_name, size_t file_size, struct im_connection *ic )
    11273{
    11374        file_transfer_t *file = g_new0( file_transfer_t, 1 );
     
    11778        file->file_name = g_strdup( file_name );
    11879        file->local_id = local_transfer_id++;
    119         df->ic = ic;
     80        file->ic = df->ic = ic;
    12081        df->ft = file;
    12182       
     
    12485
    12586/* This is where the sending magic starts... */
    126 file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, char *file_name, size_t file_size )
     87file_transfer_t *dccs_send_start( struct im_connection *ic, irc_user_t *iu, const char *file_name, size_t file_size )
    12788{
    12889        file_transfer_t *file;
    12990        dcc_file_transfer_t *df;
     91        irc_t *irc = (irc_t *) ic->bee->ui_data;
    13092        struct sockaddr_storage saddr;
    13193        char *errmsg;
     
    150112        file->status = FT_STATUS_LISTENING;
    151113
    152         if( !dccs_send_request( df, user_nick, &saddr ) )
     114        if( !dccs_send_request( df, iu, &saddr ) )
    153115                return NULL;
    154116
     
    156118        df->watch_in = b_input_add( df->fd, B_EV_IO_READ, dccs_send_proto, df );
    157119
    158         df->ic->irc->file_transfers = g_slist_prepend( df->ic->irc->file_transfers, file );
     120        irc->file_transfers = g_slist_prepend( irc->file_transfers, file );
    159121
    160122        df->progress_timeout = b_timeout_add( DCC_MAX_STALL * 1000, dcc_progress, df );
     
    163125                      "Accept the file transfer if you'd like the file. If you don't, "
    164126                      "issue the 'transfers reject' command.",
    165                       user_nick, file_name, file_size / 1024 );
     127                      iu->nick, file_name, file_size / 1024 );
    166128
    167129        return file;
     
    216178
    217179/* Creates the "DCC SEND" line and sends it to the server */
    218 int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct sockaddr_storage *saddr )
     180int dccs_send_request( struct dcc_file_transfer *df, irc_user_t *iu, struct sockaddr_storage *saddr )
    219181{
    220182        char ipaddr[INET6_ADDRSTRLEN];
     
    250212                                df->ft->file_name, ipaddr, port, df->ft->file_size );
    251213       
    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 );
     214        irc_send_msg_raw( iu, "PRIVMSG", iu->irc->user->nick, cmd );
    254215
    255216        g_free( cmd );
     
    496457 * Cleans up after a transfer.
    497458 */
    498 static void dcc_close( file_transfer_t *file )
     459void dcc_close( file_transfer_t *file )
    499460{
    500461        dcc_file_transfer_t *df = file->priv;
     462        irc_t *irc = (irc_t *) df->ic->bee->ui_data;
    501463
    502464        if( file->free )
     
    514476                b_event_remove( df->progress_timeout );
    515477       
    516         df->ic->irc->file_transfers = g_slist_remove( df->ic->irc->file_transfers, file );
     478        irc->file_transfers = g_slist_remove( irc->file_transfers, file );
    517479       
    518480        g_free( df );
     
    542504 *
    543505 */
    544 file_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;
     506file_transfer_t *dcc_request( struct im_connection *ic, char* const* ctcp )
     507{
     508        irc_t *irc = (irc_t *) ic->bee->ui_data;
    553509        file_transfer_t *ft;
    554510        dcc_file_transfer_t *df;
    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 );
     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        {
    573518                char *filename, *host, *port;
    574                 size_t filesize;
    575519                struct addrinfo hints, *rp;
    576 
    577                 /* "filename" or filename */
    578                 if ( pmatch[2].rm_so > 0 )
     520               
     521                filename = ctcp[2];
     522               
     523                host = ctcp[3];
     524                while( *host && isdigit( *host ) ) host++; /* Just digits? */
     525                if( *host == '\0' )
    579526                {
    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 ) ) };
     527                        struct in_addr ipaddr = { .s_addr = htonl( atoll( ctcp[3] ) ) };
    594528                        host = inet_ntoa( ipaddr );
    595529                } else
    596530                {
    597531                        /* Contains non-numbers, hopefully an IPV6 address */
    598                         host = input + pmatch[7].rm_so;
     532                        host = ctcp[3];
    599533                }
    600534
    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 );
     535                port = ctcp[4];
     536                filesize = atoll( ctcp[5] );
    606537
    607538                memset( &hints, 0, sizeof ( struct addrinfo ) );
     
    611542                if ( ( gret = getaddrinfo( host, port, &hints, &rp ) ) )
    612543                {
    613                         g_free( input );
    614544                        imcb_log( ic, "DCC: getaddrinfo() failed with %s "
    615545                                  "when parsing incoming 'DCC SEND': "
     
    625555
    626556                freeaddrinfo( rp );
    627                 g_free( input );
    628 
    629                 df->ic->irc->file_transfers = g_slist_prepend( df->ic->irc->file_transfers, ft );
     557
     558                irc->file_transfers = g_slist_prepend( irc->file_transfers, ft );
    630559
    631560                return ft;
    632561        }
    633 
    634         imcb_log( ic, "DCC: couldnt parse 'DCC SEND' line: %s", line );
     562        else
     563                imcb_log( ic, "DCC: couldnt parse `DCC SEND' line" );
    635564
    636565        return NULL;
    637566}
    638 
  • dcc.h

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

    r560d0a0 rf1cea66  
    593593
    594594        <bitlbee-setting name="handle_unknown" type="string" scope="global">
    595                 <default>root</default>
     595                <default>add_channel</default>
    596596                <possible-values>root, add, add_private, add_channel, ignore</possible-values>
    597597
     
    11141114
    11151115        <bitlbee-command name="identify">
    1116                 <syntax>identify &lt;password&gt;</syntax>
     1116                <syntax>identify [-noload|-force] &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).
    11261134                        </para>
    11271135                </description>
  • doc/user-guide/misc.xml

    r560d0a0 rf1cea66  
    117117</sect1>
    118118
     119<sect1 id="nick_changes">
     120<title>Changing your nickname</title>
     121
     122<para>
     123BitlBee 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>
     127The 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>
     131To 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
    119136</chapter>
  • ipc.c

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

    r560d0a0 rf1cea66  
    55  \********************************************************************/
    66
    7 /* The big hairy IRCd part of the project                               */
     7/* The IRC-based UI (for now the only one)                              */
    88
    99/*
     
    2424*/
    2525
    26 #define BITLBEE_CORE
    2726#include "bitlbee.h"
    28 #include "sock.h"
    2927#include "ipc.h"
    3028#include "dcc.h"
    3129
    32 static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond );
    33 
    34 GSList *irc_connection_list = NULL;
    35 
    36 static 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 
    51 static 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 
    96 static 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 }
     30GSList *irc_connection_list;
     31
     32static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond );
     33static char *set_eval_charset( set_t *set, char *value );
     34static char *set_eval_password( set_t *set, char *value );
    11435
    11536irc_t *irc_new( int fd )
     
    11839        struct sockaddr_storage sock;
    11940        socklen_t socklen = sizeof( sock );
     41        char *host = NULL, *myhost = NULL;
     42        irc_user_t *iu;
    12043        set_t *s;
     44        bee_t *b;
    12145       
    12246        irc = g_new0( irc_t, 1 );
     
    13054        irc->last_pong = gettime();
    13155       
    132         irc->userhash = g_hash_table_new( g_str_hash, g_str_equal );
     56        irc->nick_user_hash = g_hash_table_new( g_str_hash, g_str_equal );
    13357        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 );
    13858       
    13959        irc->iconv = (GIConv) -1;
     
    14262        if( global.conf->hostname )
    14363        {
    144                 irc->myhost = g_strdup( global.conf->hostname );
     64                myhost = g_strdup( global.conf->hostname );
    14565        }
    14666        else if( getsockname( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 )
     
    15171                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
    15272                {
    153                         irc->myhost = g_strdup( ipv6_unwrap( buf ) );
     73                        myhost = g_strdup( ipv6_unwrap( buf ) );
    15474                }
    15575        }
     
    16282                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
    16383                {
    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" );
     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" );
    17292       
    17393        if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 )
    17494                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" );
    17795
    17896        irc_connection_list = g_slist_append( irc_connection_list, irc );
    17997       
    180         s = set_add( &irc->set, "away", NULL,  set_eval_away_status, irc );
     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 );
    181115        s->flags |= SET_NULL_OK;
    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 );
     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 );
    211136       
    212137        conf_loaddefaults( irc );
    213138       
    214139        /* Evaluator sets the iconv/oconv structures. */
    215         set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) );
     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 );
    216146       
    217147        nogaim_init();
    218148       
    219         return( irc );
     149        return irc;
    220150}
    221151
     
    238168               
    239169                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
    240                                    irc->nick ? irc->nick : "(NONE)", irc->host, reason );
     170                                   irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, reason );
    241171               
    242172                g_free( reason );
     
    248178               
    249179                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
    250                                    irc->nick ? irc->nick : "(NONE)", irc->host, "No reason given" );
     180                                   irc->user->nick ? irc->user->nick : "(NONE)", irc->root->host, "No reason given" );
    251181        }
    252182       
     
    269199}
    270200
    271 static 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 */
     201static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data );
     202
    279203void irc_free( irc_t * irc )
    280204{
    281         user_t *user, *usertmp;
    282        
    283205        log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
    284206       
    285         if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->set, "save_on_quit" ) )
     207        if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) )
    286208                if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
    287                         irc_usermsg( irc, "Error while saving settings!" );
     209                        log_message( LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick );
    288210       
    289211        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         }
    305212       
    306213        while( irc->queries != NULL )
    307214                query_del( irc, irc->queries );
    308215       
    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         }
     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 );
    330226       
    331227        if( irc->ping_source_id > 0 )
     
    339235        irc->fd = -1;
    340236       
    341         g_hash_table_foreach_remove( irc->userhash, irc_free_hashkey, NULL );
    342         g_hash_table_destroy( irc->userhash );
     237        g_hash_table_foreach_remove( irc->nick_user_hash, irc_free_hashkey, NULL );
     238        g_hash_table_destroy( irc->nick_user_hash );
    343239       
    344240        g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL );
     
    352248        g_free( irc->sendbuffer );
    353249        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 );
    359250        g_free( irc->password );
    360        
    361         g_free( irc->myhost );
    362         g_free( irc->mynick );
    363        
    364         g_free( irc->channel );
    365        
    366         g_free( irc->last_target );
     251        g_free( irc->last_root_cmd );
    367252       
    368253        g_free( irc );
     
    376261}
    377262
     263static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
     264{
     265        g_free( key );
     266       
     267        return( TRUE );
     268}
     269
    378270/* USE WITH CAUTION!
    379271   Sets pass without checking */
    380 void irc_setpass (irc_t *irc, const char *pass) 
     272void irc_setpass (irc_t *irc, const char *pass)
    381273{
    382274        g_free (irc->password);
     
    389281}
    390282
     283static 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
     298static char **irc_splitlines( char *buffer );
     299
    391300void irc_process( irc_t *irc )
    392301{
     
    396305        if( irc->readbuffer != NULL )
    397306        {
    398                 lines = irc_tokenize( irc->readbuffer );
     307                lines = irc_splitlines( irc->readbuffer );
    399308               
    400309                for( i = 0; *lines[i] != '\0'; i ++ )
     
    433342                                                                  "`help set charset' for more information. Your "
    434343                                                                  "message was ignored.",
    435                                                                   set_getstr( &irc->set, "charset" ) );
     344                                                                  set_getstr( &irc->b->set, "charset" ) );
    436345                                               
    437346                                                g_free( conv );
     
    440349                                        else
    441350                                        {
    442                                                 irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost,
     351                                                irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host,
    443352                                                           "Warning: invalid characters received at login time." );
    444353                                               
     
    478387}
    479388
    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. */
    482 char **irc_tokenize( char *buffer )
     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.) */
     393static char **irc_splitlines( char *buffer )
    483394{
    484395        int i, j, n = 3;
     
    611522}
    612523
    613 void 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 
    626 int 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 
    643524void irc_write( irc_t *irc, char *format, ... )
    644525{
     
    651532        return;
    652533}
     534
     535void 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}
    653563
    654564void irc_vawrite( irc_t *irc, char *format, va_list params )
     
    707617}
    708618
    709 void 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 
    738 void 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 )
     619int irc_check_login( irc_t *irc )
     620{
     621        if( irc->user->user && irc->user->nick )
     622        {
     623                if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) )
     624                {
     625                        irc_send_num( irc, 464, ":This server is password-protected." );
     626                        return 0;
     627                }
     628                else
     629                {
     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 )
    753667                        {
    754                                 irc_reply( irc, 353, "= %s :%s", channel, namelist );
    755                                 *namelist = 0;
     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] );
    756673                        }
    757674                       
    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 
    796 int irc_check_login( irc_t *irc )
    797 {
    798         if( irc->user && irc->nick )
    799         {
    800                 if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) )
    801                 {
    802                         irc_reply( irc, 464, ":This server is password-protected." );
    803                         return 0;
    804                 }
    805                 else
    806                 {
    807                         irc_login( irc );
    808675                        return 1;
    809676                }
     
    816683}
    817684
    818 void 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 
    878 void 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 
    930 void 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 
    942 void irc_umode_set( irc_t *irc, char *s, int allow_priv )
     685void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv )
    943686{
    944687        /* allow_priv: Set to 0 if s contains user input, 1 if you want
    945688           to set a "privileged" mode (+o, +R, etc). */
    946         char m[256], st = 1, *t;
     689        char m[128], st = 1;
     690        const char *t;
    947691        int i;
    948692        char changes[512], *p, st2 = 2;
     
    952696       
    953697        for( t = irc->umode; *t; t ++ )
    954                 m[(int)*t] = 1;
    955 
     698                if( *t < sizeof( m ) )
     699                        m[(int)*t] = 1;
     700       
    956701        p = changes;
    957702        for( t = s; *t; t ++ )
     
    959704                if( *t == '+' || *t == '-' )
    960705                        st = *t == '+';
    961                 else if( st == 0 || ( strchr( UMODES, *t ) || ( allow_priv && strchr( UMODES_PRIV, *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 ) ) )
    962709                {
    963710                        if( m[(int)*t] != st)
     
    976723        memset( irc->umode, 0, sizeof( irc->umode ) );
    977724       
    978         for( i = 0; i < 256 && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
     725        for( i = 'A'; i <= 'z' && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
    979726                if( m[i] )
    980727                        irc->umode[strlen(irc->umode)] = i;
    981728       
    982729        if( badflag )
    983                 irc_reply( irc, 501, ":Unknown MODE flag" );
    984         /* Deliberately no !user@host on the prefix here */
     730                irc_send_num( irc, 501, ":Unknown MODE flag" );
    985731        if( *changes )
    986                 irc_write( irc, ":%s MODE %s %s", irc->nick, irc->nick, changes );
    987 }
    988 
    989 void irc_spawn( irc_t *irc, user_t *u )
    990 {
    991         irc_join( irc, u, irc->channel );
    992 }
    993 
    994 void 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 
    1017 void 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 
    1022 void 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 
    1027 void 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 
    1064 int 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 
    1175 static 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 
    1195 void 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 
    1240 int 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 
    1279 int 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 
    1302 int 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 );
     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 );
    1310735}
    1311736
     
    1346771}
    1347772
    1348 struct 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 }
     773static 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
     818char *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}
  • irc.h

    r560d0a0 rf1cea66  
    55  \********************************************************************/
    66
    7 /* The big hairy IRCd part of the project                               */
     7/* The IRC-based UI (for now the only one)                              */
    88
    99/*
     
    3333#define IRC_PING_STRING "PinglBee"
    3434
    35 #define UMODES "abisw"
    36 #define UMODES_PRIV "Ro"
    37 #define CMODES "nt"
    38 #define CMODE "t"
    39 #define UMODE "s"
    40 #define CTYPES "&#"
     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 */
    4143
    4244typedef enum
     
    4850        USTATUS_SHUTDOWN = 8
    4951} irc_status_t;
     52
     53struct irc_user;
    5054
    5155typedef struct irc
     
    5963        GIConv iconv, oconv;
    6064
    61         int sentbytes;
    62         time_t oldtime;
    63 
     65        struct irc_user *root;
     66        struct irc_user *user;
     67       
     68        char *last_root_cmd;
     69
     70        char *password; /* HACK: Used to save the user's password, but before
     71                           logging in, this may contain a password we should
     72                           send to identify after USER/NICK are received. */
     73
     74        char umode[8];
     75       
     76        struct query *queries;
     77        GSList *file_transfers;
     78       
     79        GSList *users, *channels;
     80        struct irc_channel *default_channel;
     81        GHashTable *nick_user_hash;
     82        GHashTable *watches;
     83
     84        gint r_watch_source_id;
     85        gint w_watch_source_id;
     86        gint ping_source_id;
     87       
     88        struct bee *b;
     89} irc_t;
     90
     91typedef enum
     92{
     93        IRC_USER_PRIVATE = 1,
     94        IRC_USER_AWAY = 2,
     95} irc_user_flags_t;
     96
     97typedef struct irc_user
     98{
     99        irc_t *irc;
     100       
    64101        char *nick;
    65102        char *user;
    66103        char *host;
    67         char *realname;
    68         char *password; /* HACK: Used to save the user's password, but before
    69                            logging in, this may contain a password we should
    70                            send to identify after USER/NICK are received. */
    71 
    72         char umode[8];
    73        
    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        
    83         struct query *queries;
    84         struct account *accounts;
    85         GSList *file_transfers;
    86         struct chat *chatrooms;
    87        
    88         struct __USER *users;
    89         GHashTable *userhash;
    90         GHashTable *watches;
    91         struct __NICK *nicks;
     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
     119struct 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
     125extern const struct irc_user_funcs irc_user_root_funcs;
     126extern const struct irc_user_funcs irc_user_self_funcs;
     127
     128typedef 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
     137typedef 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;
    92149        struct set *set;
    93 
    94         gint r_watch_source_id;
    95         gint w_watch_source_id;
    96         gint ping_source_id;
    97 } irc_t;
    98 
    99 #include "user.h"
    100 
     150       
     151        GString *pastebuf;
     152        guint pastebuf_timer;
     153       
     154        const struct irc_channel_funcs *f;
     155        void *data;
     156} irc_channel_t;
     157
     158struct 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
     170typedef 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
     177typedef struct irc_channel_user
     178{
     179        irc_user_t *iu;
     180        int flags;
     181} irc_channel_user_t;
     182
     183typedef 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
     191struct irc_control_channel
     192{
     193        irc_control_channel_type_t type;
     194        struct bee_group *group;
     195        struct account *account;
     196};
     197
     198extern const struct bee_ui_funcs irc_ui_funcs;
     199
     200/* irc.c */
    101201extern GSList *irc_connection_list;
    102202
     
    104204void irc_abort( irc_t *irc, int immed, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
    105205void irc_free( irc_t *irc );
    106 
    107 void irc_exec( irc_t *irc, char **cmd );
     206void irc_setpass (irc_t *irc, const char *pass);
     207
    108208void irc_process( irc_t *irc );
    109209char **irc_parse_line( char *line );
    110210char *irc_build_line( char **cmd );
    111211
    112 void irc_vawrite( irc_t *irc, char *format, va_list params );
    113212void irc_write( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
    114213void irc_write_all( int now, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
    115 void irc_reply( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
    116 G_MODULE_EXPORT int irc_usermsg( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
    117 char **irc_tokenize( char *buffer );
    118 
    119 void irc_login( irc_t *irc );
     214void irc_vawrite( irc_t *irc, char *format, va_list params );
     215
    120216int irc_check_login( irc_t *irc );
    121 void irc_motd( irc_t *irc );
    122 void irc_names( irc_t *irc, char *channel );
    123 void irc_topic( irc_t *irc, char *channel );
    124 void irc_umode_set( irc_t *irc, char *s, int allow_priv );
    125 void irc_who( irc_t *irc, char *channel );
    126 void irc_spawn( irc_t *irc, user_t *u );
    127 void irc_join( irc_t *irc, user_t *u, char *channel );
    128 void irc_part( irc_t *irc, user_t *u, char *channel );
    129 void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker );
    130 void irc_kill( irc_t *irc, user_t *u );
    131 void irc_invite( irc_t *irc, char *nick, char *channel );
    132 void irc_whois( irc_t *irc, char *nick );
    133 void irc_setpass( irc_t *irc, const char *pass ); /* USE WITH CAUTION! */
    134 
    135 int irc_send( irc_t *irc, char *nick, char *s, int flags );
    136 int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg );
    137 int irc_msgfrom( irc_t *irc, char *nick, char *msg );
    138 int irc_noticefrom( irc_t *irc, char *nick, char *msg );
    139 
    140 void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags );
    141 struct groupchat *irc_chat_by_channel( irc_t *irc, char *channel );
     217
     218void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv );
     219
     220/* irc_channel.c */
     221irc_channel_t *irc_channel_new( irc_t *irc, const char *name );
     222irc_channel_t *irc_channel_by_name( irc_t *irc, const char *name );
     223irc_channel_t *irc_channel_get( irc_t *irc, char *id );
     224int irc_channel_free( irc_channel_t *ic );
     225int irc_channel_add_user( irc_channel_t *ic, irc_user_t *iu );
     226int irc_channel_del_user( irc_channel_t *ic, irc_user_t *iu, gboolean silent, const char *msg );
     227irc_channel_user_t *irc_channel_has_user( irc_channel_t *ic, irc_user_t *iu );
     228int irc_channel_set_topic( irc_channel_t *ic, const char *topic, const irc_user_t *who );
     229void irc_channel_user_set_mode( irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags );
     230void irc_channel_printf( irc_channel_t *ic, char *format, ... );
     231gboolean irc_channel_name_ok( const char *name );
     232void irc_channel_update_ops( irc_channel_t *ic, char *value );
     233char *set_eval_irc_channel_ops( struct set *set, char *value );
     234
     235/* irc_commands.c */
     236void irc_exec( irc_t *irc, char **cmd );
     237
     238/* irc_send.c */
     239void irc_send_num( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
     240void irc_send_login( irc_t *irc );
     241void irc_send_motd( irc_t *irc );
     242void irc_usermsg( irc_t *irc, char *format, ... );
     243void irc_send_join( irc_channel_t *ic, irc_user_t *iu );
     244void irc_send_part( irc_channel_t *ic, irc_user_t *iu, const char *reason );
     245void irc_send_quit( irc_user_t *iu, const char *reason );
     246void irc_send_names( irc_channel_t *ic );
     247void irc_send_topic( irc_channel_t *ic, gboolean topic_change );
     248void irc_send_whois( irc_user_t *iu );
     249void irc_send_who( irc_t *irc, GSList *l, const char *channel );
     250void irc_send_msg( irc_user_t *iu, const char *type, const char *dst, const char *msg, const char *prefix );
     251void irc_send_msg_raw( irc_user_t *iu, const char *type, const char *dst, const char *msg );
     252void irc_send_msg_f( irc_user_t *iu, const char *type, const char *dst, const char *format, ... ) G_GNUC_PRINTF( 4, 5 );
     253void irc_send_nick( irc_user_t *iu, const char *new );
     254void 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 */
     258irc_user_t *irc_user_new( irc_t *irc, const char *nick );
     259int irc_user_free( irc_t *irc, irc_user_t *iu );
     260irc_user_t *irc_user_by_name( irc_t *irc, const char *nick );
     261int irc_user_set_nick( irc_user_t *iu, const char *new );
     262gint irc_user_cmp( gconstpointer a_, gconstpointer b_ );
     263const char *irc_user_get_away( irc_user_t *iu );
     264
     265/* irc_util.c */
     266char *set_eval_timezone( struct set *set, char *value );
     267char *irc_format_timestamp( irc_t *irc, time_t msg_ts );
     268
     269/* irc_im.c */
     270void bee_irc_channel_update( irc_t *irc, irc_channel_t *ic, irc_user_t *iu );
    142271
    143272#endif
  • irc_commands.c

    r560d0a0 rf1cea66  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2006 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    5353        else if( global.conf->auth_pass )
    5454        {
    55                 irc_reply( irc, 464, ":Incorrect password" );
     55                irc_send_num( irc, 464, ":Incorrect password" );
    5656        }
    5757        else
     
    6565static void irc_cmd_user( irc_t *irc, char **cmd )
    6666{
    67         irc->user = g_strdup( cmd[1] );
    68         irc->realname = g_strdup( cmd[4] );
     67        irc->user->user = g_strdup( cmd[1] );
     68        irc->user->fullname = g_strdup( cmd[4] );
    6969       
    7070        irc_check_login( irc );
     
    7373static void irc_cmd_nick( irc_t *irc, char **cmd )
    7474{
    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] );
     75        if( irc_user_by_name( irc, cmd[1] ) )
     76        {
     77                irc_send_num( irc, 433, ":This nick is already in use" );
    8478        }
    8579        else if( !nick_ok( cmd[1] ) )
    8680        {
    8781                /* [SH] Invalid characters. */
    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] );
     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] );
    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->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost );
    118 }
    119 
    120 static 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         }
     117        irc_write( irc, ":%s PONG %s :%s", irc->root->host,
     118                   irc->root->host, cmd[1]?cmd[1]:irc->root->host );
     119}
     120
     121static 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
     129static 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
     157static 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
     175static 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
     194static 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
     205static 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
     216static void irc_cmd_motd( irc_t *irc, char **cmd )
     217{
     218        irc_send_motd( irc );
    134219}
    135220
    136221static void irc_cmd_mode( irc_t *irc, char **cmd )
    137222{
    138         if( strchr( CTYPES, *cmd[1] ) )
    139         {
    140                 if( cmd[2] )
     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] )
    141230                {
    142231                        if( *cmd[2] == '+' || *cmd[2] == '-' )
    143                                 irc_reply( irc, 477, "%s :Can't change channel modes", cmd[1] );
     232                                irc_send_num( irc, 477, "%s :Can't change channel modes", cmd[1] );
    144233                        else if( *cmd[2] == 'b' )
    145                                 irc_reply( irc, 368, "%s :No bans possible", cmd[1] );
     234                                irc_send_num( irc, 368, "%s :No bans possible", cmd[1] );
    146235                }
    147236                else
    148                         irc_reply( irc, 324, "%s +%s", cmd[1], CMODE );
    149         }
    150         else
    151         {
    152                 if( nick_cmp( cmd[1], irc->nick ) == 0 )
     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 )
    153242                {
    154243                        if( cmd[2] )
    155244                                irc_umode_set( irc, cmd[2], 0 );
    156245                        else
    157                                 irc_reply( irc, 221, "+%s", irc->umode );
     246                                irc_send_num( irc, 221, "+%s", irc->umode );
    158247                }
    159248                else
    160                         irc_reply( irc, 502, ":Don't touch their modes" );
    161         }
    162 }
    163 
    164 static void irc_cmd_names( irc_t *irc, char **cmd )
    165 {
    166         irc_names( irc, cmd[1]?cmd[1]:irc->channel );
    167 }
    168 
    169 static 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 
    199 static 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 
    217 static 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 );
     249                        irc_send_num( irc, 502, ":Don't touch their modes" );
     250        }
     251}
     252
     253static 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 );
    232264}
    233265
    234266static void irc_cmd_privmsg( irc_t *irc, char **cmd )
    235267{
    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] );
     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        {
    243321        }
    244322        else
     
    281359                irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? OPT_AWAY : 0 );
    282360        }
    283 }
    284 
    285 static 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:"**" );
     361#endif
     362}
     363
     364static 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
     373static 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
     389static 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] );
    315407}
    316408
    317409static void irc_cmd_userhost( irc_t *irc, char **cmd )
    318410{
    319         user_t *u;
    320411        int i;
    321412       
     
    327418       
    328419        for( i = 1; cmd[i]; i ++ )
    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                 }
     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        }
    336428}
    337429
    338430static void irc_cmd_ison( irc_t *irc, char **cmd )
    339431{
    340         user_t *u;
    341432        char buff[IRC_MAX_LINE];
    342433        int lenleft, i;
     
    354445                while( *this )
    355446                {
     447                        irc_user_t *iu;
     448                       
    356449                        if( ( next = strchr( this, ' ' ) ) )
    357450                                *next = 0;
    358451                       
    359                         if( ( u = user_find( irc, this ) ) && u->online )
    360                         {
    361                                 lenleft -= strlen( u->nick ) + 1;
     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;
    362456                               
    363457                                if( lenleft < 0 )
    364458                                        break;
    365459                               
    366                                 strcat( buff, u->nick );
     460                                strcat( buff, iu->nick );
    367461                                strcat( buff, " " );
    368462                        }
     
    387481                buff[strlen(buff)-1] = '\0';
    388482       
    389         irc_reply( irc, 303, ":%s", buff );
     483        irc_send_num( irc, 303, ":%s", buff );
    390484}
    391485
     
    400494        {
    401495                char *nick;
    402                 user_t *u;
     496                irc_user_t *iu;
    403497               
    404498                if( !cmd[i][0] || !cmd[i][1] )
     
    408502                nick_lc( nick );
    409503               
    410                 u = user_find( irc, nick );
     504                iu = irc_user_by_name( irc, nick );
    411505               
    412506                if( cmd[i][0] == '+' )
     
    415509                                g_hash_table_insert( irc->watches, nick, nick );
    416510                       
    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" );
     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" );
    419514                        else
    420                                 irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", (int) time( NULL ), "is offline" );
     515                                irc_send_num( irc, 605, "%s %s %s %d :%s", nick, "*", "*",
     516                                              (int) time( NULL ), "is offline" );
    421517                }
    422518                else if( cmd[i][0] == '-' )
     
    429525                                g_free( okey );
    430526                               
    431                                 irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
     527                                irc_send_num( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
    432528                        }
    433529                }
     
    437533static void irc_cmd_topic( irc_t *irc, char **cmd )
    438534{
    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 );
     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 );
    453552        }
    454553}
     
    456555static void irc_cmd_away( irc_t *irc, char **cmd )
    457556{
    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         {
     557        if( cmd[1] && *cmd[1] )
     558        {
     559                char away[strlen(cmd[1])+1];
    465560                int i, j;
    466561               
    467562                /* Copy away string, but skip control chars. Mainly because
    468563                   Jabber really doesn't like them. */
    469                 u->away = g_malloc( strlen( away ) + 1 );
    470                 for( i = j = 0; away[i]; i ++ )
    471                         if( ( u->away[j] = away[i] ) >= ' ' )
     564                for( i = j = 0; cmd[1][i]; i ++ )
     565                        if( ( away[j] = cmd[1][i] ) >= ' ' )
    472566                                j ++;
    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 
    489 static 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 
    520 static 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 
    531 static 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 
    538 static void irc_cmd_motd( irc_t *irc, char **cmd )
    539 {
    540         irc_motd( irc );
    541 }
    542 
    543 static 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;
     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        }
    549577}
    550578
    551579static void irc_cmd_version( irc_t *irc, char **cmd )
    552580{
    553         irc_reply( irc, 351, "bitlbee-%s. %s :%s/%s ", BITLBEE_VERSION, irc->myhost, ARCH, CPU );
     581        irc_send_num( irc, 351, "bitlbee-%s. %s :%s/%s ",
     582                      BITLBEE_VERSION, irc->root->host, ARCH, CPU );
    554583}
    555584
    556585static void irc_cmd_completions( irc_t *irc, char **cmd )
    557586{
    558         user_t *u = user_find( irc, irc->mynick );
    559587        help_t *h;
    560588        set_t *s;
    561589        int i;
    562590       
    563         irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" );
     591        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS OK" );
    564592       
    565593        for( i = 0; commands[i].command; i ++ )
    566                 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command );
     594                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS %s", commands[i].command );
    567595       
    568596        for( h = global.help; h; h = h->next )
    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" );
     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" );
    575603}
    576604
     
    582610                ipc_to_master( cmd );
    583611       
    584         irc_reply( irc, 382, "%s :Rehashing", global.conf_file );
     612        irc_send_num( irc, 382, "%s :Rehashing", global.conf_file );
    585613}
    586614
     
    591619        { "quit",        0, irc_cmd_quit,        0 },
    592620        { "ping",        0, irc_cmd_ping,        0 },
    593         { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
     621        { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
     622        { "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 },
    594628        { "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 },
    597         { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
    598         { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
     629        { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
    599630        { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
    600         { "notice",      1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
    601         { "who",         0, irc_cmd_who,         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 },
    602636        { "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
    603637        { "ison",        1, irc_cmd_ison,        IRC_CMD_LOGGED_IN },
    604638        { "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
    605643        { "topic",       1, irc_cmd_topic,       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 },
     644        { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
    615645        { "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
    616646        { "deaf",        0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
     
    638668                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
    639669                        {
    640                                 irc_reply( irc, 462, ":Only allowed before logging in" );
     670                                irc_send_num( irc, 462, ":Only allowed before logging in" );
    641671                        }
    642672                        else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
    643673                        {
    644                                 irc_reply( irc, 451, ":Register first" );
     674                                irc_send_num( irc, 451, ":Register first" );
    645675                        }
    646676                        else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
    647677                        {
    648                                 irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" );
     678                                irc_send_num( irc, 481, ":Permission denied - You're not an IRC operator" );
    649679                        }
    650680                        else if( n_arg < irc_commands[i].required_parameters )
    651681                        {
    652                                 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
     682                                irc_send_num( irc, 461, "%s :Need more parameters", cmd[0] );
    653683                        }
    654684                        else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
     
    667697       
    668698        if( irc->status >= USTATUS_LOGGED_IN )
    669                 irc_reply( irc, 421, "%s :Unknown command", cmd[0] );
    670 }
     699                irc_send_num( irc, 421, "%s :Unknown command", cmd[0] );
     700}
  • lib/misc.c

    r560d0a0 rf1cea66  
    647647        return ret;
    648648}
     649
     650char **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

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

    r560d0a0 rf1cea66  
    7878               
    7979                nick_strip( nick );
    80                 if( set_getbool( &acc->irc->set, "lcnicks" ) )
     80                if( set_getbool( &acc->bee->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;
    9495        int inf_protection = 256;
    9596       
    9697        /* Now, find out if the nick is already in use at the moment, and make
    9798           subtle changes to make it unique. */
    98         while( !nick_ok( nick ) || user_find( acc->irc, nick ) )
     99        while( !nick_ok( nick ) || irc_user_by_name( irc, nick ) )
    99100        {
    100101                if( strlen( nick ) < ( MAX_NICK_LENGTH - 1 ) )
     
    112113                        int i;
    113114                       
    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 );
     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 );
    121122                        for( i = 0; i < MAX_NICK_LENGTH; i ++ )
    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" );
     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" );
    127128                       
    128129                        g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() );
  • protocols/Makefile

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

    r560d0a0 rf1cea66  
    107107         */
    108108        gpointer data;
     109        struct im_connection *ic;
    109110       
    110111        /*
     
    168169 * the canceled() and free() callbacks given in file will be called by this function.
    169170 */
    170 void imcb_file_canceled( file_transfer_t *file, char *reason );
     171void imcb_file_canceled( struct im_connection *ic, file_transfer_t *file, char *reason );
    171172
    172 gboolean imcb_file_recv_start( file_transfer_t *ft );
     173gboolean imcb_file_recv_start( struct im_connection *ic, file_transfer_t *ft );
    173174
    174 void imcb_file_finished( file_transfer_t *file );
     175void imcb_file_finished( struct im_connection *ic, file_transfer_t *file );
    175176#endif
  • protocols/jabber/conference.c

    r560d0a0 rf1cea66  
    9292{
    9393        char *normalized = jabber_normalize( name );
     94        GSList *l;
    9495        struct groupchat *ret;
    9596        struct jabber_chat *jc;
    9697       
    97         for( ret = ic->groupchats; ret; ret = ret->next )
    98         {
     98        for( l = ic->groupchats; l; l = l->next )
     99        {
     100                ret = l->data;
    99101                jc = ret->data;
    100102                if( strcmp( normalized, jc->name ) == 0 )
     
    103105        g_free( normalized );
    104106       
    105         return ret;
     107        return l ? ret : NULL;
    106108}
    107109
  • protocols/jabber/iq.c

    r560d0a0 rf1cea66  
    382382        while( ( c = xt_find_node( c, "item" ) ) )
    383383        {
    384                 struct xt_node *group = xt_find_node( node->children, "group" );
     384                struct xt_node *group = xt_find_node( c->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                                 if( initial || imcb_find_buddy( ic, jid ) == NULL )
    394                                         imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
    395                                                                    group->text : NULL );
     393                                imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
     394                                                           group->text : NULL );
    396395                               
    397396                                if( name )
     
    589588            strcmp( s, "result" ) == 0 )
    590589        {
    591                 if( imcb_find_buddy( ic, jid ) == NULL )
     590                if( bee_user_by_handle( ic->bee, ic, jid ) == NULL )
    592591                        imcb_add_buddy( ic, jid, NULL );
    593592        }
  • protocols/jabber/jabber.c

    r560d0a0 rf1cea66  
    267267       
    268268        while( jd->filetransfers )
    269                 imcb_file_canceled( ( ( struct jabber_transfer *) jd->filetransfers->data )->ft, "Logging out" );
     269                imcb_file_canceled( ic, ( ( 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 );
     284                jabber_chat_free( ic->groupchats->data );
    285285       
    286286        if( jd->r_inpa >= 0 )
  • protocols/jabber/jabber_util.c

    r560d0a0 rf1cea66  
    279279        presence_send_request( bla->ic, bla->handle, "subscribed" );
    280280       
    281         if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
    282                 imcb_ask_add( bla->ic, bla->handle, NULL );
     281        imcb_ask_add( bla->ic, bla->handle, NULL );
    283282       
    284283        g_free( bla->handle );
     
    462461               
    463462                if( bud == NULL && ( flags & GET_BUDDY_CREAT ) &&
    464                     ( bare_exists || imcb_find_buddy( ic, jid ) ) )
     463                    ( bare_exists || bee_user_by_handle( ic->bee, ic, jid ) ) )
    465464                {
    466465                        *s = '/';
     
    483482                if( bud == NULL )
    484483                        /* No match. Create it now? */
    485                         return ( ( flags & GET_BUDDY_CREAT ) && imcb_find_buddy( ic, jid_ ) ) ?
     484                        return ( ( flags & GET_BUDDY_CREAT ) &&
     485                                 bee_user_by_handle( ic->bee, ic, jid_ ) ) ?
    486486                                   jabber_buddy_add( ic, jid_ ) : NULL;
    487487                else if( bud->resource && ( flags & GET_BUDDY_EXACT ) )
  • protocols/jabber/presence.c

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

    r560d0a0 rf1cea66  
    567567        xt_free_node( reply );
    568568
    569         imcb_file_canceled( tf->ft, "couldn't connect to any streamhosts" );
     569        imcb_file_canceled( tf->ic, 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->ft, "Error transmitting bytestream response" );
     606                imcb_file_canceled( tf->ic, 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->ft );
     646                imcb_file_finished( tf->ic, tf->ft );
    647647
    648648        tf->ft->write( tf->ft, tf->ft->buffer, ret );   
     
    660660        if( tf->watch_in )
    661661        {
    662                 imcb_file_canceled( ft, "BUG in jabber file transfer: write_request called when already watching for input" );
     662                imcb_file_canceled( tf->ic, 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( ft );
     708                imcb_file_finished( tf->ic, 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->ft, "Error transmitting bytestream request" );
     1008                imcb_file_canceled( tf->ic, 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->ft, error );
     1023                imcb_file_canceled( tf->ic, tf->ft, error );
    10241024
    10251025        /* MUST always return FALSE! */
  • protocols/jabber/si.c

    r560d0a0 rf1cea66  
    9191
    9292        if( !foundft )
    93                 imcb_file_canceled( tf->ft, "Buddy's client doesn't feature file transfers" );
     93                imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature file transfers" );
    9494        else if( !foundbt )
    95                 imcb_file_canceled( tf->ft, "Buddy's client doesn't feature byte streams (required)" );
     95                imcb_file_canceled( tf->ic, tf->ft, "Buddy's client doesn't feature byte streams (required)" );
    9696        else if( !foundsi )
    97                 imcb_file_canceled( tf->ft, "Buddy's client doesn't feature stream initiation (required)" );
     97                imcb_file_canceled( tf->ic, 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->ft );
     111        imcb_file_recv_start( tf->ic, tf->ft );
    112112
    113113}
     
    156156        if( bud == NULL )
    157157        {
    158                 imcb_file_canceled( ft, "Couldn't find buddy (BUG?)" );
     158                imcb_file_canceled( ic, ft, "Couldn't find buddy (BUG?)" );
    159159                return;
    160160        }
  • protocols/msn/Makefile

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

    r560d0a0 rf1cea66  
    7979        if( md )
    8080        {
     81                /** Disabling MSN ft support for now.
    8182                while( md->filetransfers ) {
    8283                        imcb_file_canceled( md->filetransfers->data, "Closing connection" );
    8384                }
     85                */
    8486               
    8587                if( md->fd >= 0 )
     
    221223{
    222224        struct msn_switchboard *sb;
     225        struct groupchat *c = imcb_chat_new( ic, who );
    223226       
    224227        if( ( sb = msn_sb_by_handle( ic, who ) ) )
     
    238241                msn_sb_write_msg( ic, m );
    239242
    240                 return NULL;
    241         }
    242        
    243         return NULL;
     243                return c;
     244        }
    244245}
    245246
     
    332333        ret->send_typing = msn_send_typing;
    333334        ret->handle_cmp = g_strcasecmp;
    334         ret->transfer_request = msn_ftp_transfer_request;
     335        //ret->transfer_request = msn_ftp_transfer_request;
    335336
    336337        register_protocol(ret);
  • protocols/msn/msn_util.c

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

    r560d0a0 rf1cea66  
    175175                        i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user );
    176176                }
     177                else if( strcmp( text, SB_KEEPALIVE_MESSAGE ) == 0 )
     178                {
     179                        buf = g_strdup( SB_KEEPALIVE_HEADERS );
     180                        i = strlen( buf );
     181                }
    177182                else if( strncmp( text, MSN_INVITE_HEADERS, sizeof( MSN_INVITE_HEADERS ) - 1 ) == 0 )
    178183                {
    179184                        buf = g_strdup( text );
    180                         i = strlen( buf );
    181                 }
    182                 else if( strcmp( text, SB_KEEPALIVE_MESSAGE ) == 0 )
    183                 {
    184                         buf = g_strdup( SB_KEEPALIVE_HEADERS );
    185185                        i = strlen( buf );
    186186                }
     
    233233{
    234234        struct im_connection *ic = sb->ic;
     235        struct groupchat *c = NULL;
    235236        char buf[1024];
    236237       
    237238        /* Create the groupchat structure. */
    238239        g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session );
    239         sb->chat = imcb_chat_new( ic, buf );
     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 );
    240246       
    241247        /* Populate the channel. */
     
    698704                        }
    699705                }
     706#if 0
     707                // Disable MSN ft support for now.
    700708                else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 )
    701709                {
     
    730738                        g_free( command );
    731739                }
     740#endif
    732741                else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 )
    733742                {
     
    765774void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial )
    766775{
    767         struct buddy *b;
     776        bee_user_t *bu;
    768777       
    769778        if( sb && sb->who && sb->keepalive == 0 &&
    770             ( b = imcb_find_buddy( sb->ic, sb->who ) ) && !b->present &&
     779            ( bu = bee_user_by_handle( sb->ic->bee, sb->ic, sb->who ) ) &&
     780            !( bu->flags & BEE_USER_ONLINE ) &&
    771781            set_getbool( &sb->ic->acc->set, "switchboard_keepalives" ) )
    772782        {
  • protocols/nogaim.c

    r560d0a0 rf1cea66  
    3838#include "chat.h"
    3939
    40 static int remove_chat_buddy_silent( struct groupchat *b, const char *handle );
    41 static char *format_timestamp( irc_t *irc, time_t msg_ts );
    42 
    4340GSList *connections;
    4441
     
    9289}
    9390#endif
    94 
    95 /* nogaim.c */
    9691
    9792GList *protocols = NULL;
     
    129124}
    130125
    131 /* nogaim.c */
    132126void nogaim_init()
    133127{
     
    158152        twitter_initmodule();
    159153#endif
    160        
     154
    161155#ifdef WITH_PURPLE
    162156        purple_initmodule();
     
    170164GSList *get_connections() { return connections; }
    171165
    172 /* multi.c */
    173 
    174166struct im_connection *imcb_new( account_t *acc )
    175167{
     
    178170        ic = g_new0( struct im_connection, 1 );
    179171       
    180         ic->irc = acc->irc;
     172        ic->bee = acc->bee;
    181173        ic->acc = acc;
    182174        acc->ic = ic;
     
    192184       
    193185        /* Destroy the pointer to this connection from the account list */
    194         for( a = ic->irc->accounts; a; a = a->next )
     186        for( a = ic->bee->accounts; a; a = a->next )
    195187                if( a->ic == ic )
    196188                {
     
    213205        va_end( params );
    214206
    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" ) ) )
     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" ) ) )
    217209                strip_html( text );
    218210       
    219211        /* Try to find a different connection on the same protocol. */
    220         for( a = ic->irc->accounts; a; a = a->next )
     212        for( a = ic->bee->accounts; a; a = a->next )
    221213                if( a->prpl == ic->acc->prpl && a->ic != ic )
    222214                        break;
     
    224216        /* If we found one, include the screenname in the message. */
    225217        if( a )
    226                 irc_usermsg( ic->irc, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
     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 );
    227220        else
    228                 irc_usermsg( ic->irc, "%s - %s", ic->acc->prpl->name, text );
     221                irc_usermsg( ic->bee->ui_data, "%s - %s", ic->acc->prpl->name, text );
    229222       
    230223        g_free( text );
     
    277270void imcb_connected( struct im_connection *ic )
    278271{
    279         irc_t *irc = ic->irc;
    280         struct chat *c;
    281         user_t *u;
    282        
    283272        /* MSN servers sometimes redirect you to a different server and do
    284273           the whole login sequence again, so these "late" calls to this
     
    287276                return;
    288277       
    289         u = user_find( ic->irc, ic->irc->nick );
    290        
    291278        imcb_log( ic, "Logged in" );
    292279       
     
    301288        ic->acc->auto_reconnect_delay = 0;
    302289       
     290        /*
    303291        for( c = irc->chatrooms; c; c = c->next )
    304292        {
     
    309297                        chat_join( irc, c, NULL );
    310298        }
     299        */
    311300}
    312301
     
    316305       
    317306        a->reconnect = 0;
    318         account_on( a->irc, a );
     307        account_on( a->bee, a );
    319308       
    320309        return( FALSE );        /* Only have to run the timeout once */
     
    329318void imc_logout( struct im_connection *ic, int allow_reconnect )
    330319{
    331         irc_t *irc = ic->irc;
    332         user_t *t, *u;
     320        bee_t *bee = ic->bee;
    333321        account_t *a;
     322        GSList *l;
    334323        int delay;
    335324       
     
    351340        ic->away = NULL;
    352341       
    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 )
     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 )
    369356                if( a->ic == ic )
    370357                        break;
     
    374361                /* Uhm... This is very sick. */
    375362        }
    376         else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) &&
     363        else if( allow_reconnect && set_getbool( &bee->set, "auto_reconnect" ) &&
    377364                 set_getbool( &a->set, "auto_reconnect" ) &&
    378365                 ( delay = account_reconnect_delay( a ) ) > 0 )
     
    385372}
    386373
    387 
    388 /* dialogs.c */
    389 
    390374void imcb_ask( struct im_connection *ic, char *msg, void *data,
    391375               query_callback doit, query_callback dont )
    392376{
    393         query_add( ic->irc, ic, msg, doit, dont, data );
    394 }
    395 
    396 
    397 /* list.c */
     377        query_add( (irc_t *) ic->bee->ui_data, ic, msg, doit, dont, data );
     378}
    398379
    399380void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group )
    400381{
    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 );
     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
     394void 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 );
    409405               
    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 
    454 struct 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 
    473 void 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 );
     406                if( bee->ui->user_fullname )
     407                        bee->ui->user_fullname( bee, bu );
    505408        }
    506409}
     
    508411void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group )
    509412{
    510         user_t *u;
    511        
    512         if( ( u = user_findhandle( ic, handle ) ) )
    513                 user_del( ic->irc, u->nick );
     413        bee_user_free( ic->bee, bee_user_by_handle( ic->bee, ic, handle ) );
    514414}
    515415
     
    518418void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick )
    519419{
    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         }
     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 );
    551427}
    552428
     
    593469        data->ic = ic;
    594470        data->handle = g_strdup( handle );
    595         query_add( ic->irc, ic, s, imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
     471        query_add( (irc_t *) ic->bee->ui_data, ic, s,
     472                   imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
    596473}
    597474
     
    618495       
    619496        /* TODO: Make a setting for this! */
    620         if( user_findhandle( ic, handle ) != NULL )
     497        if( bee_user_by_handle( ic->bee, ic, handle ) != NULL )
    621498                return;
    622499       
     
    625502        data->ic = ic;
    626503        data->handle = g_strdup( 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 
    633 void 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 
    789 void 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 
    849 void 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 
    865 struct 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 
    890 void 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 
    919 void 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 
    960 void 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 
    992 void 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 
    1010 void 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 
    1036 void 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 */
    1071 void 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 
    1098 static 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 
    1122 char *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 
    1177 char *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 
    1215 static 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 );
     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
     508struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle )
     509{
     510        return bee_user_by_handle( ic->bee, ic, handle );
    1264511}
    1265512
    1266513/* The plan is to not allow straight calls to prpl functions anymore, but do
    1267514   them all from some wrappers. We'll start to define some down here: */
    1268 
    1269 int 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 }
    1285515
    1286516int imc_chat_msg( struct groupchat *c, char *msg, int flags )
     
    1311541       
    1312542        away = set_getstr( &ic->acc->set, "away" ) ?
    1313              : set_getstr( &ic->irc->set, "away" );
     543             : set_getstr( &ic->bee->set, "away" );
    1314544        if( away && *away )
    1315545        {
     
    1322552                away = NULL;
    1323553                msg = set_getstr( &ic->acc->set, "status" ) ?
    1324                     : set_getstr( &ic->irc->set, "status" );
     554                    : set_getstr( &ic->bee->set, "status" );
    1325555        }
    1326556       
  • protocols/nogaim.h

    r560d0a0 rf1cea66  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    8787       
    8888        /* BitlBee */
    89         irc_t *irc;
    90        
    91         struct groupchat *groupchats;
     89        bee_t *bee;
     90       
     91        GSList *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;
    105         char *channel;
     102        //GList *ignored;
     103       
     104        //struct groupchat *next;
    106105        /* The title variable contains the ID you gave when you created the
    107106         * chat using imcb_chat_new(). */
     
    114113         * structure for your protocol's needs. */
    115114        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 */
    294 G_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. */
    297 G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at );
    298289G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags );
     290G_MODULE_EXPORT struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle );
    299291G_MODULE_EXPORT void imcb_clean_handle( struct im_connection *ic, char *handle );
    300292
     
    322314/* Actions, or whatever. */
    323315int imc_away_send_update( struct im_connection *ic );
    324 int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags );
    325316int imc_chat_msg( struct groupchat *c, char *msg, int flags );
    326317
  • protocols/oscar/oscar.c

    r560d0a0 rf1cea66  
    254254
    255255        u = t = g_strdup(s);
    256 
    257         strcpy(t, s);
    258256        g_strdown(t);
    259257
     
    652650        struct im_connection *ic = sess->aux_data;
    653651        struct chat_connection *chatcon;
     652        struct groupchat *c = NULL;
    654653        static int id = 1;
    655654
     
    664663        chatcon = find_oscar_chat_by_conn(ic, fr->conn);
    665664        chatcon->id = id;
    666         chatcon->cnv = imcb_chat_new(ic, chatcon->show);
     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);
    667671        chatcon->cnv->data = chatcon;
    668672
     
    934938        tmp = normalize(info->sn);
    935939        imcb_buddy_status(ic, tmp, flags, state_string, NULL);
    936         /* imcb_buddy_times(ic, tmp, signon, time_idle); */
     940        imcb_buddy_times(ic, tmp, signon, time_idle);
    937941
    938942
     
    10601064        aim_ssi_auth_reply(od->sess, od->conn, uin, 1, "");
    10611065        // aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHGRANTED, &message);
    1062         if(imcb_find_buddy(data->ic, uin) == NULL)
    1063                 imcb_ask_add(data->ic, uin, NULL);
     1066        imcb_ask_add(data->ic, uin, NULL);
    10641067       
    10651068        g_free(uin);
     
    18221825        struct oscar_data *odata = (struct oscar_data *)g->proto_data;
    18231826        if (odata->icq) {
     1827                /** FIXME(wilmer): Hmm, lost the ability to get away msgs here, do we care to get that back?
    18241828                struct buddy *budlight = imcb_find_buddy(g, who);
    18251829                if (budlight)
     
    18271831                                if (budlight->caps & AIM_CAPS_ICQSERVERRELAY)
    18281832                                        aim_send_im_ch2_geticqmessage(odata->sess, who, (budlight->uc & 0xff80) >> 7);
     1833                */
    18291834        } else
    18301835                aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_AWAYMESSAGE);
     
    19531958static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {
    19541959        struct im_connection *ic = sess->aux_data;
    1955         struct aim_ssi_item *curitem;
     1960        struct aim_ssi_item *curitem, *curgroup;
    19561961        int tmp;
    19571962        char *nrm;
     
    19641969                switch (curitem->type) {
    19651970                        case 0x0000: /* Buddy */
    1966                                 if ((curitem->name) && (!imcb_find_buddy(ic, nrm))) {
     1971                                if ((curitem->name) && (!imcb_buddy_by_handle(ic, nrm))) {
    19671972                                        char *realname = NULL;
    19681973
    19691974                                        if (curitem->data && aim_gettlv(curitem->data, 0x0131, 1))
    19701975                                                    realname = aim_gettlv_str(curitem->data, 0x0131, 1);
    1971                                                
    1972                                         imcb_add_buddy(ic, nrm, NULL);
     1976                                       
     1977                                        imcb_add_buddy(ic, nrm, curgroup->gid == curitem->gid ? curgroup->name : NULL);
    19731978                                       
    19741979                                        if (realname) {
     
    19781983                                        }
    19791984                                }
     1985                                break;
     1986
     1987                        case 0x0001: /* Group */
     1988                                curgroup = curitem;
    19801989                                break;
    19811990
     
    25202529        static int chat_id = 0;
    25212530        char * chatname;
     2531        struct groupchat *c;
    25222532       
    25232533        chatname = g_strdup_printf("%s%s_%d", isdigit(*ic->acc->user) ? "icq_" : "",
    25242534                                   ic->acc->user, chat_id++);
    2525  
     2535       
     2536        c = imcb_chat_new(ic, chatname);
    25262537        ret = oscar_chat_join(ic, chatname, NULL, NULL);
    2527 
    25282538        aim_chat_invite(od->sess, od->conn, who, "", 4, chatname, 0x0);
    25292539
  • protocols/purple/ft.c

    r560d0a0 rf1cea66  
    7575                px->fn = mktemp( g_strdup( "/tmp/bitlbee-purple-ft.XXXXXX" ) );
    7676                px->fd = -1;
     77                px->ic = purple_ic_by_pa( xfer->account );
    7778               
    7879                purple_xfer_set_local_filename( xfer, px->fn );
     
    143144                {
    144145                        purple_xfer_cancel_local( px->xfer );
    145                         imcb_file_canceled( ft, "Read error" );
     146                        imcb_file_canceled( px->ic, ft, "Read error" );
    146147                }
    147148        }
     
    150151        {
    151152                /*purple_xfer_end( px->xfer );*/
    152                 imcb_file_finished( ft );
     153                imcb_file_finished( px->ic, ft );
    153154        }
    154155       
     
    230231       
    231232        if( px->ft )
    232                 imcb_file_canceled( px->ft, "Canceled by remote end" );
     233                imcb_file_canceled( px->ic, px->ft, "Canceled by remote end" );
    233234        else
    234235                /* px->ft == NULL for sends, because of the two stages. :-/ */
     
    301302{
    302303        file_transfer_t *ft = data;
     304        struct prpl_xfer_data *px = ft->data;
    303305       
    304306        if( ft->write == NULL )
    305307        {
    306308                ft->write = prpl_xfer_write;
    307                 imcb_file_recv_start( ft );
     309                imcb_file_recv_start( px->ic, ft );
    308310        }
    309311       
     
    319321        if( write( px->fd, buffer, len ) != len )
    320322        {
    321                 imcb_file_canceled( ft, "Error while writing temporary file" );
     323                imcb_file_canceled( px->ic, ft, "Error while writing temporary file" );
    322324                return FALSE;
    323325        }
     
    329331               
    330332                purple_transfer_forward( ft );
    331                 imcb_file_finished( ft );
     333                imcb_file_finished( px->ic, ft );
    332334                px->ft = NULL;
    333335        }
  • protocols/purple/purple.c

    r560d0a0 rf1cea66  
    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 irc_t *local_irc;
     37static bee_t *local_bee;
    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.
    159161                        irc_usermsg( acc->irc, "Setting with unknown type: %s (%d) Expect stuff to break..\n",
    160162                                     name, purple_account_option_get_type( o ) );
     163                        */
    161164                        name = NULL;
    162165                }
     
    251254        PurpleAccount *pa;
    252255       
    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." );
     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 );
    257261                return;
    258262        }
    259         local_irc = acc->irc;
     263        local_bee = acc->bee;
    260264       
    261265        /* For now this is needed in the _connected() handlers if using
     
    683687                imcb_buddy_status( ic, bud->name, flags, purple_status_get_name( as ),
    684688                                   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 ) );
    685693        }
    686694}
     
    866874        pqad->user_data = user_data;
    867875       
     876        /* TODO: IRC stuff here :-( */
    868877        q = g_strdup_printf( "Request: %s\n\n%s\n\n%s", title, primary, secondary );
    869         pqad->bee_data = query_add( local_irc, purple_ic_by_pa( account ), q,
     878        pqad->bee_data = query_add( local_bee->ui_data, purple_ic_by_pa( account ), q,
    870879                prplcb_request_action_yes, prplcb_request_action_no, pqad );
    871880       
  • protocols/twitter/twitter_lib.c

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

    r560d0a0 rf1cea66  
    158158       
    159159        while( ic->groupchats )
    160                 imcb_chat_free( ic->groupchats );
     160                imcb_chat_free( ic->groupchats->data );
    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...
    616615        if( stat == YAHOO_STATUS_IDLE )
    617                 imcb_buddy_times( ic, who, 0, away );
    618         */
     616                imcb_buddy_times( ic, who, 0, idle );
    619617}
    620618
     
    796794        struct byahoo_conf_invitation *inv = data;
    797795        struct groupchat *b;
    798        
    799         for( b = inv->ic->groupchats; b; b = b->next )
     796        GSList *l;
     797       
     798        for( l = inv->ic->groupchats; l; l = l->next )
     799        {
     800                b = l->data;
    800801                if( b == inv->c )
    801802                        break;
     803        }
    802804       
    803805        if( b != NULL )
     
    865867{
    866868        struct im_connection *ic = byahoo_get_ic_by_id( id );
    867         struct groupchat *c;
    868        
    869         for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
     869        struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
    870870       
    871871        if( c )
     
    877877{
    878878        struct im_connection *ic = byahoo_get_ic_by_id( id );
    879         struct groupchat *c;
    880        
    881         for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
     879        struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
    882880       
    883881        if( c )
     
    889887        struct im_connection *ic = byahoo_get_ic_by_id( id );
    890888        char *m = byahoo_strip( msg );
    891         struct groupchat *c;
    892        
    893         for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
     889        struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
    894890       
    895891        if( c )
  • query.c

    r560d0a0 rf1cea66  
    6464        }
    6565       
    66         if( g_strcasecmp( set_getstr( &irc->set, "query_order" ), "lifo" ) == 0 || irc->queries == q )
     66        if( g_strcasecmp( set_getstr( &irc->b->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->set, "query_order" ), "fifo" ) == 0 )
     181        if( g_strcasecmp( set_getstr( &irc->b->set, "query_order" ), "fifo" ) == 0 )
    182182                q = irc->queries;
    183183        else
  • root_commands.c

    r560d0a0 rf1cea66  
    3232#include <string.h>
    3333
    34 void 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 );
     34void root_command_string( irc_t *irc, char *command )
     35{
     36        root_command( irc, split_command_parts( command ) );
    7837}
    7938
     
    9251void root_command( irc_t *irc, char *cmd[] )
    9352{       
    94         int i;
     53        int i, len;
    9554       
    9655        if( !cmd[0] )
    9756                return;
    9857       
     58        len = strlen( cmd[0] );
    9959        for( i = 0; commands[i].command; i++ )
    100                 if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
    101                 {
     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                       
    10267                        MIN_ARGS( commands[i].required_parameters );
    10368                       
     
    140105static void cmd_identify( irc_t *irc, char **cmd )
    141106{
    142         storage_status_t status = storage_load( irc, cmd[1] );
     107        storage_status_t status;
    143108        char *account_on[] = { "account", "on", NULL };
    144        
    145         if( strchr( irc->umode, 'R' ) != NULL )
     109        gboolean load = TRUE;
     110        char *password = cmd[1];
     111       
     112        if( irc->status & USTATUS_IDENTIFIED )
    146113        {
    147114                irc_usermsg( irc, "You're already logged in." );
    148115                return;
    149116        }
     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 );
    150146       
    151147        switch (status) {
     
    157153                break;
    158154        case STORAGE_OK:
    159                 irc_usermsg( irc, "Password accepted, settings and accounts loaded" );
    160                 irc_setpass( irc, cmd[1] );
     155                irc_usermsg( irc, "Password accepted%s",
     156                             load ? ", settings and accounts loaded" : "" );
     157                irc_setpass( irc, password );
    161158                irc->status |= USTATUS_IDENTIFIED;
    162159                irc_umode_set( irc, "+R", 1 );
    163                 if( set_getbool( &irc->set, "auto_connect" ) )
     160                if( load && set_getbool( &irc->b->set, "auto_connect" ) )
    164161                        cmd_account( irc, account_on );
    165162                break;
     
    201198        storage_status_t status;
    202199       
    203         status = storage_remove (irc->nick, cmd[1]);
     200        status = storage_remove (irc->user->nick, cmd[1]);
    204201        switch (status) {
    205202        case STORAGE_NO_SUCH_USER:
     
    213210                irc->status &= ~USTATUS_IDENTIFIED;
    214211                irc_umode_set( irc, "-R", 1 );
    215                 irc_usermsg( irc, "Account `%s' removed", irc->nick );
     212                irc_usermsg( irc, "Account `%s' removed", irc->user->nick );
    216213                break;
    217214        default:
     
    221218}
    222219
    223 struct cmd_account_del_data
    224 {
    225         account_t *a;
    226         irc_t *irc;
    227 };
    228 
    229 void 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 
    252 void cmd_account_del_no( void *data )
    253 {
    254         g_free( data );
     220static 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!" );
    255228}
    256229
     
    285258                set_name = set_full;
    286259               
    287                 head = &irc->set;
     260                head = &irc->b->set;
    288261        }
    289262        else
     
    356329        account_t *a;
    357330       
    358         if( ( a = account_get( irc, id ) ) )
     331        if( ( a = account_get( irc->b, id ) ) )
    359332                return &a->set;
    360333        else
     
    404377                }
    405378
    406                 a = account_add( irc, prpl, cmd[3], cmd[4] );
     379                a = account_add( irc->b, prpl, cmd[3], cmd[4] );
    407380                if( cmd[5] )
    408381                {
     
    418391                MIN_ARGS( 2 );
    419392
    420                 if( !( a = account_get( irc, cmd[2] ) ) )
     393                if( !( a = account_get( irc->b, cmd[2] ) ) )
    421394                {
    422395                        irc_usermsg( irc, "Invalid account" );
     
    428401                else
    429402                {
    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 );
     403                        account_del( irc->b, a );
     404                        irc_usermsg( irc, "Account deleted" );
    444405                }
    445406        }
     
    451412                        irc_usermsg( irc, "Account list:" );
    452413               
    453                 for( a = irc->accounts; a; a = a->next )
     414                for( a = irc->b->accounts; a; a = a->next )
    454415                {
    455416                        char *con;
     
    474435                if( cmd[2] )
    475436                {
    476                         if( ( a = account_get( irc, cmd[2] ) ) )
     437                        if( ( a = account_get( irc->b, cmd[2] ) ) )
    477438                        {
    478439                                if( a->ic )
     
    483444                                else
    484445                                {
    485                                         account_on( irc, a );
     446                                        account_on( irc->b, a );
    486447                                }
    487448                        }
     
    494455                else
    495456                {
    496                         if ( irc->accounts ) {
     457                        if ( irc->b->accounts )
     458                        {
    497459                                irc_usermsg( irc, "Trying to get all accounts connected..." );
    498460                       
    499                                 for( a = irc->accounts; a; a = a->next )
     461                                for( a = irc->b->accounts; a; a = a->next )
    500462                                        if( !a->ic && a->auto_connect )
    501                                                 account_on( irc, a );
     463                                                account_on( irc->b, a );
    502464                        }
    503465                        else
     
    513475                        irc_usermsg( irc, "Deactivating all active (re)connections..." );
    514476                       
    515                         for( a = irc->accounts; a; a = a->next )
     477                        for( a = irc->b->accounts; a; a = a->next )
    516478                        {
    517479                                if( a->ic )
    518                                         account_off( irc, a );
     480                                        account_off( irc->b, a );
    519481                                else if( a->reconnect )
    520482                                        cancel_auto_reconnect( a );
    521483                        }
    522484                }
    523                 else if( ( a = account_get( irc, cmd[2] ) ) )
     485                else if( ( a = account_get( irc->b, cmd[2] ) ) )
    524486                {
    525487          &nb