source: root_commands.c @ ca0981a

Last change on this file since ca0981a was 767a148, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-03-21T16:06:31Z

Merging in file transfer support. Most important points from my review
are fixed now, time to let it settle in and get people to try it.

  • Property mode set to 100644
File size: 28.3 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* User manager (root) commands                                         */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#define BITLBEE_CORE
27#include "commands.h"
28#include "crypting.h"
29#include "bitlbee.h"
30#include "help.h"
31#include "chat.h"
32
33#include <string.h>
34
35void root_command_string( irc_t *irc, user_t *u, char *command, int flags )
36{
37        char *cmd[IRC_MAX_ARGS];
38        char *s;
39        int k;
40        char q = 0;
41       
42        memset( cmd, 0, sizeof( cmd ) );
43        cmd[0] = command;
44        k = 1;
45        for( s = command; *s && k < ( IRC_MAX_ARGS - 1 ); s ++ )
46                if( *s == ' ' && !q )
47                {
48                        *s = 0;
49                        while( *++s == ' ' );
50                        if( *s == '"' || *s == '\'' )
51                        {
52                                q = *s;
53                                s ++;
54                        }
55                        if( *s )
56                        {
57                                cmd[k++] = s;
58                                s --;
59                        }
60                        else
61                        {
62                                break;
63                        }
64                }
65                else if( *s == '\\' && ( ( !q && s[1] ) || ( q && q == s[1] ) ) )
66                {
67                        char *cpy;
68                       
69                        for( cpy = s; *cpy; cpy ++ )
70                                cpy[0] = cpy[1];
71                }
72                else if( *s == q )
73                {
74                        q = *s = 0;
75                }
76        cmd[k] = NULL;
77       
78        root_command( irc, cmd );
79}
80
81#define MIN_ARGS( x, y... )                                                    \
82        do                                                                     \
83        {                                                                      \
84                int blaat;                                                     \
85                for( blaat = 0; blaat <= x; blaat ++ )                         \
86                        if( cmd[blaat] == NULL )                               \
87                        {                                                      \
88                                irc_usermsg( irc, "Not enough parameters given (need %d).", x ); \
89                                return y;                                      \
90                        }                                                      \
91        } while( 0 )
92
93void root_command( irc_t *irc, char *cmd[] )
94{       
95        int i;
96       
97        if( !cmd[0] )
98                return;
99       
100        for( i = 0; commands[i].command; i++ )
101                if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
102                {
103                        MIN_ARGS( commands[i].required_parameters );
104                       
105                        commands[i].execute( irc, cmd );
106                        return;
107                }
108       
109        irc_usermsg( irc, "Unknown command: %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[0] );
110}
111
112static void cmd_help( irc_t *irc, char **cmd )
113{
114        char param[80];
115        int i;
116        char *s;
117       
118        memset( param, 0, sizeof(param) );
119        for ( i = 1; (cmd[i] != NULL && ( strlen(param) < (sizeof(param)-1) ) ); i++ ) {
120                if ( i != 1 )   // prepend space except for the first parameter
121                        strcat(param, " ");
122                strncat( param, cmd[i], sizeof(param) - strlen(param) - 1 );
123        }
124
125        s = help_get( &(global.help), param );
126        if( !s ) s = help_get( &(global.help), "" );
127       
128        if( s )
129        {
130                irc_usermsg( irc, "%s", s );
131                g_free( s );
132        }
133        else
134        {
135                irc_usermsg( irc, "Error opening helpfile." );
136        }
137}
138
139static void cmd_account( irc_t *irc, char **cmd );
140
141static void cmd_identify( irc_t *irc, char **cmd )
142{
143        storage_status_t status = storage_load( irc, cmd[1] );
144        char *account_on[] = { "account", "on", NULL };
145       
146        if( strchr( irc->umode, 'R' ) != NULL )
147        {
148                irc_usermsg( irc, "You're already logged in." );
149                return;
150        }
151       
152        switch (status) {
153        case STORAGE_INVALID_PASSWORD:
154                irc_usermsg( irc, "Incorrect password" );
155                break;
156        case STORAGE_NO_SUCH_USER:
157                irc_usermsg( irc, "The nick is (probably) not registered" );
158                break;
159        case STORAGE_OK:
160                irc_usermsg( irc, "Password accepted, settings and accounts loaded" );
161                irc_setpass( irc, cmd[1] );
162                irc->status |= USTATUS_IDENTIFIED;
163                irc_umode_set( irc, "+R", 1 );
164                if( set_getbool( &irc->set, "auto_connect" ) )
165                        cmd_account( irc, account_on );
166                break;
167        case STORAGE_OTHER_ERROR:
168        default:
169                irc_usermsg( irc, "Unknown error while loading configuration" );
170                break;
171        }
172}
173
174static void cmd_register( irc_t *irc, char **cmd )
175{
176        if( global.conf->authmode == AUTHMODE_REGISTERED )
177        {
178                irc_usermsg( irc, "This server does not allow registering new accounts" );
179                return;
180        }
181
182        switch( storage_save( irc, cmd[1], FALSE ) ) {
183                case STORAGE_ALREADY_EXISTS:
184                        irc_usermsg( irc, "Nick is already registered" );
185                        break;
186                       
187                case STORAGE_OK:
188                        irc_usermsg( irc, "Account successfully created" );
189                        irc_setpass( irc, cmd[1] );
190                        irc->status |= USTATUS_IDENTIFIED;
191                        irc_umode_set( irc, "+R", 1 );
192                        break;
193
194                default:
195                        irc_usermsg( irc, "Error registering" );
196                        break;
197        }
198}
199
200static void cmd_drop( irc_t *irc, char **cmd )
201{
202        storage_status_t status;
203       
204        status = storage_remove (irc->nick, cmd[1]);
205        switch (status) {
206        case STORAGE_NO_SUCH_USER:
207                irc_usermsg( irc, "That account does not exist" );
208                break;
209        case STORAGE_INVALID_PASSWORD:
210                irc_usermsg( irc, "Password invalid" );
211                break;
212        case STORAGE_OK:
213                irc_setpass( irc, NULL );
214                irc->status &= ~USTATUS_IDENTIFIED;
215                irc_umode_set( irc, "-R", 1 );
216                irc_usermsg( irc, "Account `%s' removed", irc->nick );
217                break;
218        default:
219                irc_usermsg( irc, "Error: `%d'", status );
220                break;
221        }
222}
223
224struct cmd_account_del_data
225{
226        account_t *a;
227        irc_t *irc;
228};
229
230void cmd_account_del_yes( void *data )
231{
232        struct cmd_account_del_data *cad = data;
233        account_t *a;
234       
235        for( a = cad->irc->accounts; a && a != cad->a; a = a->next );
236       
237        if( a == NULL )
238        {
239                irc_usermsg( cad->irc, "Account already deleted" );
240        }
241        else if( a->ic )
242        {
243                irc_usermsg( cad->irc, "Account is still logged in, can't delete" );
244        }
245        else
246        {
247                account_del( cad->irc, a );
248                irc_usermsg( cad->irc, "Account deleted" );
249        }
250        g_free( data );
251}
252
253void cmd_account_del_no( void *data )
254{
255        g_free( data );
256}
257
258static void cmd_showset( irc_t *irc, set_t **head, char *key )
259{
260        char *val;
261       
262        if( ( val = set_getstr( head, key ) ) )
263                irc_usermsg( irc, "%s = `%s'", key, val );
264        else
265                irc_usermsg( irc, "%s is empty", key );
266}
267
268typedef set_t** (*cmd_set_findhead)( irc_t*, char* );
269typedef int (*cmd_set_checkflags)( irc_t*, set_t *set );
270
271static int cmd_set_real( irc_t *irc, char **cmd, cmd_set_findhead findhead, cmd_set_checkflags checkflags )
272{
273        char *set_full = NULL, *set_name = NULL, *tmp;
274        set_t **head;
275       
276        if( cmd[1] && g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
277        {
278                MIN_ARGS( 2, 0 );
279                set_full = cmd[2];
280        }
281        else
282                set_full = cmd[1];
283       
284        if( findhead == NULL )
285        {
286                set_name = set_full;
287               
288                head = &irc->set;
289        }
290        else 
291        {
292                char *id;
293               
294                if( ( tmp = strchr( set_full, '/' ) ) )
295                {
296                        id = g_strndup( set_full, ( tmp - set_full ) );
297                        set_name = tmp + 1;
298                }
299                else
300                {
301                        id = g_strdup( set_full );
302                }
303               
304                if( ( head = findhead( irc, id ) ) == NULL )
305                {
306                        g_free( id );
307                        irc_usermsg( irc, "Could not find setting." );
308                        return 0;
309                }
310                g_free( id );
311        }
312       
313        if( cmd[1] && cmd[2] && set_name )
314        {
315                set_t *s = set_find( head, set_name );
316                int st;
317               
318                if( s && checkflags && checkflags( irc, s ) == 0 )
319                        return 0;
320               
321                if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
322                        st = set_reset( head, set_name );
323                else
324                        st = set_setstr( head, set_name, cmd[2] );
325               
326                if( set_getstr( head, set_name ) == NULL )
327                {
328                        if( st )
329                                irc_usermsg( irc, "Setting changed successfully" );
330                        else
331                                irc_usermsg( irc, "Failed to change setting" );
332                }
333                else
334                {
335                        cmd_showset( irc, head, set_name );
336                }
337        }
338        else if( set_name )
339        {
340                cmd_showset( irc, head, set_name );
341        }
342        else
343        {
344                set_t *s = *head;
345                while( s )
346                {
347                        cmd_showset( irc, &s, s->key );
348                        s = s->next;
349                }
350        }
351       
352        return 1;
353}
354
355static set_t **cmd_account_set_findhead( irc_t *irc, char *id )
356{
357        account_t *a;
358       
359        if( ( a = account_get( irc, id ) ) )
360                return &a->set;
361        else
362                return NULL;
363}
364
365static int cmd_account_set_checkflags( irc_t *irc, set_t *s )
366{
367        account_t *a = s->data;
368       
369        if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY )
370        {
371                irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" );
372                return 0;
373        }
374        else if( !a->ic && s && s->flags & ACC_SET_ONLINE_ONLY )
375        {
376                irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" );
377                return 0;
378        }
379       
380        return 1;
381}
382
383static void cmd_account( irc_t *irc, char **cmd )
384{
385        account_t *a;
386       
387        if( global.conf->authmode == AUTHMODE_REGISTERED && !( irc->status & USTATUS_IDENTIFIED ) )
388        {
389                irc_usermsg( irc, "This server only accepts registered users" );
390                return;
391        }
392       
393        if( g_strcasecmp( cmd[1], "add" ) == 0 )
394        {
395                struct prpl *prpl;
396               
397                MIN_ARGS( 4 );
398               
399                prpl = find_protocol( cmd[2] );
400               
401                if( prpl == NULL )
402                {
403                        irc_usermsg( irc, "Unknown protocol" );
404                        return;
405                }
406
407                a = account_add( irc, prpl, cmd[3], cmd[4] );
408                if( cmd[5] )
409                {
410                        irc_usermsg( irc, "Warning: Passing a servername/other flags to `account add' "
411                                          "is now deprecated. Use `account set' instead." );
412                        set_setstr( &a->set, "server", cmd[5] );
413                }
414               
415                irc_usermsg( irc, "Account successfully added" );
416        }
417        else if( g_strcasecmp( cmd[1], "del" ) == 0 )
418        {
419                MIN_ARGS( 2 );
420
421                if( !( a = account_get( irc, cmd[2] ) ) )
422                {
423                        irc_usermsg( irc, "Invalid account" );
424                }
425                else if( a->ic )
426                {
427                        irc_usermsg( irc, "Account is still logged in, can't delete" );
428                }
429                else
430                {
431                        struct cmd_account_del_data *cad;
432                        char *msg;
433                       
434                        cad = g_malloc( sizeof( struct cmd_account_del_data ) );
435                        cad->a = a;
436                        cad->irc = irc;
437                       
438                        msg = g_strdup_printf( "If you remove this account (%s(%s)), BitlBee will "
439                                               "also forget all your saved nicknames. If you want "
440                                               "to change your username/password, use the `account "
441                                               "set' command. Are you sure you want to delete this "
442                                               "account?", a->prpl->name, a->user );
443                        query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, cad );
444                        g_free( msg );
445                }
446        }
447        else if( g_strcasecmp( cmd[1], "list" ) == 0 )
448        {
449                int i = 0;
450               
451                if( strchr( irc->umode, 'b' ) )
452                        irc_usermsg( irc, "Account list:" );
453               
454                for( a = irc->accounts; a; a = a->next )
455                {
456                        char *con;
457                       
458                        if( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) )
459                                con = " (connected)";
460                        else if( a->ic )
461                                con = " (connecting)";
462                        else if( a->reconnect )
463                                con = " (awaiting reconnect)";
464                        else
465                                con = "";
466                       
467                        irc_usermsg( irc, "%2d. %s, %s%s", i, a->prpl->name, a->user, con );
468                       
469                        i ++;
470                }
471                irc_usermsg( irc, "End of account list" );
472        }
473        else if( g_strcasecmp( cmd[1], "on" ) == 0 )
474        {
475                if( cmd[2] )
476                {
477                        if( ( a = account_get( irc, cmd[2] ) ) )
478                        {
479                                if( a->ic )
480                                {
481                                        irc_usermsg( irc, "Account already online" );
482                                        return;
483                                }
484                                else
485                                {
486                                        account_on( irc, a );
487                                }
488                        }
489                        else
490                        {
491                                irc_usermsg( irc, "Invalid account" );
492                                return;
493                        }
494                }
495                else
496                {
497                        if ( irc->accounts ) {
498                                irc_usermsg( irc, "Trying to get all accounts connected..." );
499                       
500                                for( a = irc->accounts; a; a = a->next )
501                                        if( !a->ic && a->auto_connect )
502                                                account_on( irc, a );
503                        } 
504                        else
505                        {
506                                irc_usermsg( irc, "No accounts known. Use `account add' to add one." );
507                        }
508                }
509        }
510        else if( g_strcasecmp( cmd[1], "off" ) == 0 )
511        {
512                if( !cmd[2] )
513                {
514                        irc_usermsg( irc, "Deactivating all active (re)connections..." );
515                       
516                        for( a = irc->accounts; a; a = a->next )
517                        {
518                                if( a->ic )
519                                        account_off( irc, a );
520                                else if( a->reconnect )
521                                        cancel_auto_reconnect( a );
522                        }
523                }
524                else if( ( a = account_get( irc, cmd[2] ) ) )
525                {
526                        if( a->ic )
527                        {
528                                account_off( irc, a );
529                        }
530                        else if( a->reconnect )
531                        {
532                                cancel_auto_reconnect( a );
533                                irc_usermsg( irc, "Reconnect cancelled" );
534                        }
535                        else
536                        {
537                                irc_usermsg( irc, "Account already offline" );
538                                return;
539                        }
540                }
541                else
542                {
543                        irc_usermsg( irc, "Invalid account" );
544                        return;
545                }
546        }
547        else if( g_strcasecmp( cmd[1], "set" ) == 0 )
548        {
549                MIN_ARGS( 2 );
550               
551                cmd_set_real( irc, cmd + 1, cmd_account_set_findhead, cmd_account_set_checkflags );
552        }
553        else
554        {
555                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "account", cmd[1] );
556        }
557}
558
559static void cmd_add( irc_t *irc, char **cmd )
560{
561        account_t *a;
562        int add_on_server = 1;
563       
564        if( g_strcasecmp( cmd[1], "-tmp" ) == 0 )
565        {
566                MIN_ARGS( 3 );
567                add_on_server = 0;
568                cmd ++;
569        }
570       
571        if( !( a = account_get( irc, cmd[1] ) ) )
572        {
573                irc_usermsg( irc, "Invalid account" );
574                return;
575        }
576        else if( !( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) ) )
577        {
578                irc_usermsg( irc, "That account is not on-line" );
579                return;
580        }
581       
582        if( cmd[3] )
583        {
584                if( !nick_ok( cmd[3] ) )
585                {
586                        irc_usermsg( irc, "The requested nick `%s' is invalid", cmd[3] );
587                        return;
588                }
589                else if( user_find( irc, cmd[3] ) )
590                {
591                        irc_usermsg( irc, "The requested nick `%s' already exists", cmd[3] );
592                        return;
593                }
594                else
595                {
596                        nick_set( a, cmd[2], cmd[3] );
597                }
598        }
599       
600        if( add_on_server )
601                a->ic->acc->prpl->add_buddy( a->ic, cmd[2], NULL );
602        else
603                /* Yeah, officially this is a call-*back*... So if we just
604                   called add_buddy, we'll wait for the IM server to respond
605                   before we do this. */
606                imcb_add_buddy( a->ic, cmd[2], NULL );
607       
608        irc_usermsg( irc, "Adding `%s' to your contact list", cmd[2]  );
609}
610
611static void cmd_info( irc_t *irc, char **cmd )
612{
613        struct im_connection *ic;
614        account_t *a;
615       
616        if( !cmd[2] )
617        {
618                user_t *u = user_find( irc, cmd[1] );
619                if( !u || !u->ic )
620                {
621                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
622                        return;
623                }
624                ic = u->ic;
625                cmd[2] = u->handle;
626        }
627        else if( !( a = account_get( irc, cmd[1] ) ) )
628        {
629                irc_usermsg( irc, "Invalid account" );
630                return;
631        }
632        else if( !( ( ic = a->ic ) && ( a->ic->flags & OPT_LOGGED_IN ) ) )
633        {
634                irc_usermsg( irc, "That account is not on-line" );
635                return;
636        }
637       
638        if( !ic->acc->prpl->get_info )
639        {
640                irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
641        }
642        else
643        {
644                ic->acc->prpl->get_info( ic, cmd[2] );
645        }
646}
647
648static void cmd_rename( irc_t *irc, char **cmd )
649{
650        user_t *u;
651       
652        if( g_strcasecmp( cmd[1], irc->nick ) == 0 )
653        {
654                irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] );
655        }
656        else if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
657        {
658                if( strchr( CTYPES, cmd[2][0] ) && nick_ok( cmd[2] + 1 ) )
659                {
660                        u = user_find( irc, irc->nick );
661                       
662                        irc_part( irc, u, irc->channel );
663                        g_free( irc->channel );
664                        irc->channel = g_strdup( cmd[2] );
665                        irc_join( irc, u, irc->channel );
666                       
667                        if( strcmp( cmd[0], "set_rename" ) != 0 )
668                                set_setstr( &irc->set, "control_channel", cmd[2] );
669                }
670        }
671        else if( user_find( irc, cmd[2] ) && ( nick_cmp( cmd[1], cmd[2] ) != 0 ) )
672        {
673                irc_usermsg( irc, "Nick `%s' already exists", cmd[2] );
674        }
675        else if( !nick_ok( cmd[2] ) )
676        {
677                irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] );
678        }
679        else if( !( u = user_find( irc, cmd[1] ) ) )
680        {
681                irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
682        }
683        else
684        {
685                user_rename( irc, cmd[1], cmd[2] );
686                irc_write( irc, ":%s!%s@%s NICK %s", cmd[1], u->user, u->host, cmd[2] );
687                if( g_strcasecmp( cmd[1], irc->mynick ) == 0 )
688                {
689                        g_free( irc->mynick );
690                        irc->mynick = g_strdup( cmd[2] );
691                       
692                        /* If we're called internally (user did "set root_nick"),
693                           let's not go O(INF). :-) */
694                        if( strcmp( cmd[0], "set_rename" ) != 0 )
695                                set_setstr( &irc->set, "root_nick", cmd[2] );
696                }
697                else if( u->send_handler == buddy_send_handler )
698                {
699                        nick_set( u->ic->acc, u->handle, cmd[2] );
700                }
701               
702                irc_usermsg( irc, "Nick successfully changed" );
703        }
704}
705
706char *set_eval_root_nick( set_t *set, char *new_nick )
707{
708        irc_t *irc = set->data;
709       
710        if( strcmp( irc->mynick, new_nick ) != 0 )
711        {
712                char *cmd[] = { "set_rename", irc->mynick, new_nick, NULL };
713               
714                cmd_rename( irc, cmd );
715        }
716       
717        return strcmp( irc->mynick, new_nick ) == 0 ? new_nick : SET_INVALID;
718}
719
720char *set_eval_control_channel( set_t *set, char *new_name )
721{
722        irc_t *irc = set->data;
723       
724        if( strcmp( irc->channel, new_name ) != 0 )
725        {
726                char *cmd[] = { "set_rename", irc->channel, new_name, NULL };
727               
728                cmd_rename( irc, cmd );
729        }
730       
731        return strcmp( irc->channel, new_name ) == 0 ? new_name : SET_INVALID;
732}
733
734static void cmd_remove( irc_t *irc, char **cmd )
735{
736        user_t *u;
737        char *s;
738       
739        if( !( u = user_find( irc, cmd[1] ) ) || !u->ic )
740        {
741                irc_usermsg( irc, "Buddy `%s' not found", cmd[1] );
742                return;
743        }
744        s = g_strdup( u->handle );
745       
746        u->ic->acc->prpl->remove_buddy( u->ic, u->handle, NULL );
747        nick_del( u->ic->acc, u->handle );
748        user_del( irc, cmd[1] );
749       
750        irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
751        g_free( s );
752       
753        return;
754}
755
756static void cmd_block( irc_t *irc, char **cmd )
757{
758        struct im_connection *ic;
759        account_t *a;
760       
761        if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->ic )
762        {
763                char *format;
764                GSList *l;
765               
766                if( strchr( irc->umode, 'b' ) != NULL )
767                        format = "%s\t%s";
768                else
769                        format = "%-32.32s  %-16.16s";
770               
771                irc_usermsg( irc, format, "Handle", "Nickname" );
772                for( l = a->ic->deny; l; l = l->next )
773                {
774                        user_t *u = user_findhandle( a->ic, l->data );
775                        irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" );
776                }
777                irc_usermsg( irc, "End of list." );
778               
779                return;
780        }
781        else if( !cmd[2] )
782        {
783                user_t *u = user_find( irc, cmd[1] );
784                if( !u || !u->ic )
785                {
786                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
787                        return;
788                }
789                ic = u->ic;
790                cmd[2] = u->handle;
791        }
792        else if( !( a = account_get( irc, cmd[1] ) ) )
793        {
794                irc_usermsg( irc, "Invalid account" );
795                return;
796        }
797        else if( !( ( ic = a->ic ) && ( a->ic->flags & OPT_LOGGED_IN ) ) )
798        {
799                irc_usermsg( irc, "That account is not on-line" );
800                return;
801        }
802       
803        if( !ic->acc->prpl->add_deny || !ic->acc->prpl->rem_permit )
804        {
805                irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
806        }
807        else
808        {
809                imc_rem_allow( ic, cmd[2] );
810                imc_add_block( ic, cmd[2] );
811                irc_usermsg( irc, "Buddy `%s' moved from your allow- to your block-list", cmd[2] );
812        }
813}
814
815static void cmd_allow( irc_t *irc, char **cmd )
816{
817        struct im_connection *ic;
818        account_t *a;
819       
820        if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->ic )
821        {
822                char *format;
823                GSList *l;
824               
825                if( strchr( irc->umode, 'b' ) != NULL )
826                        format = "%s\t%s";
827                else
828                        format = "%-32.32s  %-16.16s";
829               
830                irc_usermsg( irc, format, "Handle", "Nickname" );
831                for( l = a->ic->permit; l; l = l->next )
832                {
833                        user_t *u = user_findhandle( a->ic, l->data );
834                        irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" );
835                }
836                irc_usermsg( irc, "End of list." );
837               
838                return;
839        }
840        else if( !cmd[2] )
841        {
842                user_t *u = user_find( irc, cmd[1] );
843                if( !u || !u->ic )
844                {
845                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
846                        return;
847                }
848                ic = u->ic;
849                cmd[2] = u->handle;
850        }
851        else if( !( a = account_get( irc, cmd[1] ) ) )
852        {
853                irc_usermsg( irc, "Invalid account" );
854                return;
855        }
856        else if( !( ( ic = a->ic ) && ( a->ic->flags & OPT_LOGGED_IN ) ) )
857        {
858                irc_usermsg( irc, "That account is not on-line" );
859                return;
860        }
861       
862        if( !ic->acc->prpl->rem_deny || !ic->acc->prpl->add_permit )
863        {
864                irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
865        }
866        else
867        {
868                imc_rem_block( ic, cmd[2] );
869                imc_add_allow( ic, cmd[2] );
870               
871                irc_usermsg( irc, "Buddy `%s' moved from your block- to your allow-list", cmd[2] );
872        }
873}
874
875static void cmd_yesno( irc_t *irc, char **cmd )
876{
877        query_t *q = NULL;
878        int numq = 0;
879       
880        if( irc->queries == NULL )
881        {
882                irc_usermsg( irc, "Did I ask you something?" );
883                return;
884        }
885       
886        /* If there's an argument, the user seems to want to answer another question than the
887           first/last (depending on the query_order setting) one. */
888        if( cmd[1] )
889        {
890                if( sscanf( cmd[1], "%d", &numq ) != 1 )
891                {
892                        irc_usermsg( irc, "Invalid query number" );
893                        return;
894                }
895               
896                for( q = irc->queries; q; q = q->next, numq -- )
897                        if( numq == 0 )
898                                break;
899               
900                if( !q )
901                {
902                        irc_usermsg( irc, "Uhm, I never asked you something like that..." );
903                        return;
904                }
905        }
906       
907        if( g_strcasecmp( cmd[0], "yes" ) == 0 )
908                query_answer( irc, q, 1 );
909        else if( g_strcasecmp( cmd[0], "no" ) == 0 )
910                query_answer( irc, q, 0 );
911}
912
913static void cmd_set( irc_t *irc, char **cmd )
914{
915        cmd_set_real( irc, cmd, NULL, NULL );
916}
917
918static void cmd_save( irc_t *irc, char **cmd )
919{
920        if( ( irc->status & USTATUS_IDENTIFIED ) == 0 )
921                irc_usermsg( irc, "Please create an account first" );
922        else if( storage_save( irc, NULL, TRUE ) == STORAGE_OK )
923                irc_usermsg( irc, "Configuration saved" );
924        else
925                irc_usermsg( irc, "Configuration could not be saved!" );
926}
927
928static void cmd_blist( irc_t *irc, char **cmd )
929{
930        int online = 0, away = 0, offline = 0;
931        user_t *u;
932        char s[256];
933        char *format;
934        int n_online = 0, n_away = 0, n_offline = 0;
935       
936        if( cmd[1] && g_strcasecmp( cmd[1], "all" ) == 0 )
937                online = offline = away = 1;
938        else if( cmd[1] && g_strcasecmp( cmd[1], "offline" ) == 0 )
939                offline = 1;
940        else if( cmd[1] && g_strcasecmp( cmd[1], "away" ) == 0 )
941                away = 1;
942        else if( cmd[1] && g_strcasecmp( cmd[1], "online" ) == 0 )
943                online = 1;
944        else
945                online = away = 1;
946       
947        if( strchr( irc->umode, 'b' ) != NULL )
948                format = "%s\t%s\t%s";
949        else
950                format = "%-16.16s  %-40.40s  %s";
951       
952        irc_usermsg( irc, format, "Nick", "User/Host/Network", "Status" );
953       
954        for( u = irc->users; u; u = u->next ) if( u->ic && u->online && !u->away )
955        {
956                if( online == 1 )
957                {
958                        char st[256] = "Online";
959                       
960                        if( u->status_msg )
961                                g_snprintf( st, sizeof( st ) - 1, "Online (%s)", u->status_msg );
962                       
963                        g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user );
964                        irc_usermsg( irc, format, u->nick, s, st );
965                }
966               
967                n_online ++;
968        }
969
970        for( u = irc->users; u; u = u->next ) if( u->ic && u->online && u->away )
971        {
972                if( away == 1 )
973                {
974                        g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user );
975                        irc_usermsg( irc, format, u->nick, s, u->away );
976                }
977                n_away ++;
978        }
979       
980        for( u = irc->users; u; u = u->next ) if( u->ic && !u->online )
981        {
982                if( offline == 1 )
983                {
984                        g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user );
985                        irc_usermsg( irc, format, u->nick, s, "Offline" );
986                }
987                n_offline ++;
988        }
989       
990        irc_usermsg( irc, "%d buddies (%d available, %d away, %d offline)", n_online + n_away + n_offline, n_online, n_away, n_offline );
991}
992
993static void cmd_nick( irc_t *irc, char **cmd ) 
994{
995        account_t *a;
996
997        if( !cmd[1] || !( a = account_get( irc, cmd[1] ) ) )
998        {
999                irc_usermsg( irc, "Invalid account");
1000        }
1001        else if( !( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) ) )
1002        {
1003                irc_usermsg( irc, "That account is not on-line" );
1004        }
1005        else if ( !cmd[2] ) 
1006        {
1007                irc_usermsg( irc, "Your name is `%s'" , a->ic->displayname ? a->ic->displayname : "NULL" );
1008        }
1009        else if ( !a->prpl->set_my_name ) 
1010        {
1011                irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
1012        }
1013        else
1014        {
1015                irc_usermsg( irc, "Setting your name to `%s'", cmd[2] );
1016               
1017                a->prpl->set_my_name( a->ic, cmd[2] );
1018        }
1019}
1020
1021static void cmd_qlist( irc_t *irc, char **cmd )
1022{
1023        query_t *q = irc->queries;
1024        int num;
1025       
1026        if( !q )
1027        {
1028                irc_usermsg( irc, "There are no pending questions." );
1029                return;
1030        }
1031       
1032        irc_usermsg( irc, "Pending queries:" );
1033       
1034        for( num = 0; q; q = q->next, num ++ )
1035                if( q->ic ) /* Not necessary yet, but it might come later */
1036                        irc_usermsg( irc, "%d, %s(%s): %s", num, q->ic->acc->prpl->name, q->ic->acc->user, q->question );
1037                else
1038                        irc_usermsg( irc, "%d, BitlBee: %s", num, q->question );
1039}
1040
1041static void cmd_join_chat( irc_t *irc, char **cmd )
1042{
1043        irc_usermsg( irc, "This command is now obsolete. "
1044                          "Please try the `chat' command instead." );
1045}
1046
1047static set_t **cmd_chat_set_findhead( irc_t *irc, char *id )
1048{
1049        struct chat *c;
1050       
1051        if( ( c = chat_get( irc, id ) ) )
1052                return &c->set;
1053        else
1054                return NULL;
1055}
1056
1057static void cmd_chat( irc_t *irc, char **cmd )
1058{
1059        account_t *acc;
1060        struct chat *c;
1061       
1062        if( g_strcasecmp( cmd[1], "add" ) == 0 )
1063        {
1064                char *channel, *s;
1065               
1066                MIN_ARGS( 3 );
1067               
1068                if( !( acc = account_get( irc, cmd[2] ) ) )
1069                {
1070                        irc_usermsg( irc, "Invalid account" );
1071                        return;
1072                }
1073               
1074                if( cmd[4] == NULL )
1075                {
1076                        channel = g_strdup( cmd[3] );
1077                        if( ( s = strchr( channel, '@' ) ) )
1078                                *s = 0;
1079                }
1080                else
1081                {
1082                        channel = g_strdup( cmd[4] );
1083                }
1084               
1085                if( strchr( CTYPES, channel[0] ) == NULL )
1086                {
1087                        s = g_strdup_printf( "%c%s", CTYPES[0], channel );
1088                        g_free( channel );
1089                        channel = s;
1090                }
1091               
1092                if( ( c = chat_add( irc, acc, cmd[3], channel ) ) )
1093                        irc_usermsg( irc, "Chatroom added successfully." );
1094                else
1095                        irc_usermsg( irc, "Could not add chatroom." );
1096               
1097                g_free( channel );
1098        }
1099        else if( g_strcasecmp( cmd[1], "list" ) == 0 )
1100        {
1101                int i = 0;
1102               
1103                if( strchr( irc->umode, 'b' ) )
1104                        irc_usermsg( irc, "Chatroom list:" );
1105               
1106                for( c = irc->chatrooms; c; c = c->next )
1107                {
1108                        irc_usermsg( irc, "%2d. %s(%s) %s, %s", i, c->acc->prpl->name,
1109                                          c->acc->user, c->handle, c->channel );
1110                       
1111                        i ++;
1112                }
1113                irc_usermsg( irc, "End of chatroom list" );
1114        }
1115        else if( g_strcasecmp( cmd[1], "set" ) == 0 )
1116        {
1117                MIN_ARGS( 2 );
1118               
1119                cmd_set_real( irc, cmd + 1, cmd_chat_set_findhead, NULL );
1120        }
1121        else if( g_strcasecmp( cmd[1], "del" ) == 0 )
1122        {
1123                MIN_ARGS( 2 );
1124               
1125                if( ( c = chat_get( irc, cmd[2] ) ) )
1126                {
1127                        chat_del( irc, c );
1128                }
1129                else
1130                {
1131                        irc_usermsg( irc, "Could not remove chat." );
1132                }
1133        }
1134        else if( g_strcasecmp( cmd[1], "with" ) == 0 )
1135        {
1136                user_t *u;
1137               
1138                MIN_ARGS( 2 );
1139               
1140                if( ( u = user_find( irc, cmd[2] ) ) && u->ic && u->ic->acc->prpl->chat_with )
1141                {
1142                        if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) )
1143                        {
1144                                irc_usermsg( irc, "(Possible) failure while trying to open "
1145                                                  "a groupchat with %s.", u->nick );
1146                        }
1147                }
1148                else
1149                {
1150                        irc_usermsg( irc, "Can't open a groupchat with %s.", cmd[2] );
1151                }
1152        }
1153        else
1154        {
1155                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "chat", cmd[1] );
1156        }
1157}
1158
1159static void cmd_transfer( irc_t *irc, char **cmd )
1160{
1161        GSList *files = irc->file_transfers;
1162        enum { LIST, REJECT, CANCEL };
1163        int subcmd = LIST;
1164        int fid;
1165
1166        if( !files )
1167        {
1168                irc_usermsg( irc, "No pending transfers" );
1169                return;
1170        }
1171
1172        if( cmd[1] && ( strcmp( cmd[1], "reject" ) == 0 ) )
1173        {
1174                subcmd = REJECT;
1175        }
1176        else if( cmd[1] && ( strcmp( cmd[1], "cancel" ) == 0 ) && 
1177                 cmd[2] && ( sscanf( cmd[2], "%d", &fid ) == 1 ) )
1178        {
1179                subcmd = CANCEL;
1180        }
1181
1182        for( ; files; files = g_slist_next( files ) )
1183        {
1184                file_transfer_t *file = files->data;
1185               
1186                switch( subcmd ) {
1187                case LIST:
1188                        if ( file->status == FT_STATUS_LISTENING )
1189                                irc_usermsg( irc, 
1190                                        "Pending file(id %d): %s (Listening...)", file->local_id, file->file_name);
1191                        else 
1192                        {
1193                                int kb_per_s = 0;
1194                                time_t diff = time( NULL ) - file->started ? : 1;
1195                                if ( ( file->started > 0 ) && ( file->bytes_transferred > 0 ) )
1196                                        kb_per_s = file->bytes_transferred / 1024 / diff;
1197                                       
1198                                irc_usermsg( irc, 
1199                                        "Pending file(id %d): %s (%10zd/%zd kb, %d kb/s)", file->local_id, file->file_name, 
1200                                        file->bytes_transferred/1024, file->file_size/1024, kb_per_s);
1201                        }
1202                        break;
1203                case REJECT:
1204                        if( file->status == FT_STATUS_LISTENING )
1205                        {
1206                                irc_usermsg( irc, "Rejecting file transfer for %s", file->file_name );
1207                                imcb_file_canceled( file, "Denied by user" );
1208                        }
1209                        break;
1210                case CANCEL:
1211                        if( file->local_id == fid )
1212                        {
1213                                irc_usermsg( irc, "Canceling file transfer for %s", file->file_name );
1214                                imcb_file_canceled( file, "Canceled by user" );
1215                        }
1216                        break;
1217                }
1218        }
1219}
1220
1221const command_t commands[] = {
1222        { "help",           0, cmd_help,           0 }, 
1223        { "identify",       1, cmd_identify,       0 },
1224        { "register",       1, cmd_register,       0 },
1225        { "drop",           1, cmd_drop,           0 },
1226        { "account",        1, cmd_account,        0 },
1227        { "add",            2, cmd_add,            0 },
1228        { "info",           1, cmd_info,           0 },
1229        { "rename",         2, cmd_rename,         0 },
1230        { "remove",         1, cmd_remove,         0 },
1231        { "block",          1, cmd_block,          0 },
1232        { "allow",          1, cmd_allow,          0 },
1233        { "save",           0, cmd_save,           0 },
1234        { "set",            0, cmd_set,            0 },
1235        { "yes",            0, cmd_yesno,          0 },
1236        { "no",             0, cmd_yesno,          0 },
1237        { "blist",          0, cmd_blist,          0 },
1238        { "nick",           1, cmd_nick,           0 },
1239        { "qlist",          0, cmd_qlist,          0 },
1240        { "join_chat",      2, cmd_join_chat,      0 },
1241        { "chat",           1, cmd_chat,           0 },
1242        { "transfer",       0, cmd_transfer,       0 },
1243        { NULL }
1244};
Note: See TracBrowser for help on using the repository browser.