source: root_commands.c @ e907683

Last change on this file since e907683 was e907683, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-06-26T23:39:31Z

Changed account set (and other account commands) syntax. Instead of
"account set acc/key value" you now do "account acc set key value". So just
the regular set syntax with a "account acc" prefix. The slash has been a
source of confusion for long enough now.

For consistency, commands like "account on acc" should now also be
"account acc on" instead. Same for the new "channel" comand, of course.

  • Property mode set to 100644
File size: 27.6 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 "bitlbee.h"
29#include "help.h"
30#include "chat.h"
31
32#include <string.h>
33
34void root_command_string( irc_t *irc, char *command )
35{
36        root_command( irc, split_command_parts( command ) );
37}
38
39#define MIN_ARGS( x, y... )                                                    \
40        do                                                                     \
41        {                                                                      \
42                int blaat;                                                     \
43                for( blaat = 0; blaat <= x; blaat ++ )                         \
44                        if( cmd[blaat] == NULL )                               \
45                        {                                                      \
46                                irc_usermsg( irc, "Not enough parameters given (need %d).", x ); \
47                                return y;                                      \
48                        }                                                      \
49        } while( 0 )
50
51void root_command( irc_t *irc, char *cmd[] )
52{       
53        int i, len;
54       
55        if( !cmd[0] )
56                return;
57       
58        len = strlen( cmd[0] );
59        for( i = 0; commands[i].command; i++ )
60                if( g_strncasecmp( commands[i].command, cmd[0], len ) == 0 )
61                {
62                        if( commands[i+1].command &&
63                            g_strncasecmp( commands[i+1].command, cmd[0], len ) == 0 )
64                                /* Only match on the first letters if the match is unique. */
65                                break;
66                       
67                        MIN_ARGS( commands[i].required_parameters );
68                       
69                        commands[i].execute( irc, cmd );
70                        return;
71                }
72       
73        irc_usermsg( irc, "Unknown command: %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[0] );
74}
75
76static void cmd_help( irc_t *irc, char **cmd )
77{
78        char param[80];
79        int i;
80        char *s;
81       
82        memset( param, 0, sizeof(param) );
83        for ( i = 1; (cmd[i] != NULL && ( strlen(param) < (sizeof(param)-1) ) ); i++ ) {
84                if ( i != 1 )   // prepend space except for the first parameter
85                        strcat(param, " ");
86                strncat( param, cmd[i], sizeof(param) - strlen(param) - 1 );
87        }
88
89        s = help_get( &(global.help), param );
90        if( !s ) s = help_get( &(global.help), "" );
91       
92        if( s )
93        {
94                irc_usermsg( irc, "%s", s );
95                g_free( s );
96        }
97        else
98        {
99                irc_usermsg( irc, "Error opening helpfile." );
100        }
101}
102
103static void cmd_account( irc_t *irc, char **cmd );
104
105static void cmd_identify( irc_t *irc, char **cmd )
106{
107        storage_status_t status;
108        char *account_on[] = { "account", "on", NULL };
109        gboolean load = TRUE;
110        char *password = cmd[1];
111       
112        if( irc->status & USTATUS_IDENTIFIED )
113        {
114                irc_usermsg( irc, "You're already logged in." );
115                return;
116        }
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 );
146       
147        switch (status) {
148        case STORAGE_INVALID_PASSWORD:
149                irc_usermsg( irc, "Incorrect password" );
150                break;
151        case STORAGE_NO_SUCH_USER:
152                irc_usermsg( irc, "The nick is (probably) not registered" );
153                break;
154        case STORAGE_OK:
155                irc_usermsg( irc, "Password accepted%s",
156                             load ? ", settings and accounts loaded" : "" );
157                irc_setpass( irc, password );
158                irc->status |= USTATUS_IDENTIFIED;
159                irc_umode_set( irc, "+R", 1 );
160                if( load && set_getbool( &irc->b->set, "auto_connect" ) )
161                        cmd_account( irc, account_on );
162                break;
163        case STORAGE_OTHER_ERROR:
164        default:
165                irc_usermsg( irc, "Unknown error while loading configuration" );
166                break;
167        }
168}
169
170static void cmd_register( irc_t *irc, char **cmd )
171{
172        if( global.conf->authmode == AUTHMODE_REGISTERED )
173        {
174                irc_usermsg( irc, "This server does not allow registering new accounts" );
175                return;
176        }
177
178        switch( storage_save( irc, cmd[1], FALSE ) ) {
179                case STORAGE_ALREADY_EXISTS:
180                        irc_usermsg( irc, "Nick is already registered" );
181                        break;
182                       
183                case STORAGE_OK:
184                        irc_usermsg( irc, "Account successfully created" );
185                        irc_setpass( irc, cmd[1] );
186                        irc->status |= USTATUS_IDENTIFIED;
187                        irc_umode_set( irc, "+R", 1 );
188                        break;
189
190                default:
191                        irc_usermsg( irc, "Error registering" );
192                        break;
193        }
194}
195
196static void cmd_drop( irc_t *irc, char **cmd )
197{
198        storage_status_t status;
199       
200        status = storage_remove (irc->user->nick, cmd[1]);
201        switch (status) {
202        case STORAGE_NO_SUCH_USER:
203                irc_usermsg( irc, "That account does not exist" );
204                break;
205        case STORAGE_INVALID_PASSWORD:
206                irc_usermsg( irc, "Password invalid" );
207                break;
208        case STORAGE_OK:
209                irc_setpass( irc, NULL );
210                irc->status &= ~USTATUS_IDENTIFIED;
211                irc_umode_set( irc, "-R", 1 );
212                irc_usermsg( irc, "Account `%s' removed", irc->user->nick );
213                break;
214        default:
215                irc_usermsg( irc, "Error: `%d'", status );
216                break;
217        }
218}
219
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!" );
228}
229
230static void cmd_showset( irc_t *irc, set_t **head, char *key )
231{
232        char *val;
233       
234        if( ( val = set_getstr( head, key ) ) )
235                irc_usermsg( irc, "%s = `%s'", key, val );
236        else
237                irc_usermsg( irc, "%s is empty", key );
238}
239
240typedef set_t** (*cmd_set_findhead)( irc_t*, char* );
241typedef int (*cmd_set_checkflags)( irc_t*, set_t *set );
242
243static int cmd_set_real( irc_t *irc, char **cmd, set_t **head, cmd_set_checkflags checkflags )
244{
245        char *set_name = NULL, *value = NULL;
246        gboolean del = FALSE;
247       
248        if( cmd[1] && g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
249        {
250                MIN_ARGS( 2, 0 );
251                set_name = cmd[2];
252                del = TRUE;
253        }
254        else
255        {
256                set_name = cmd[1];
257                value = cmd[2];
258        }
259       
260        if( set_name && ( value || del ) )
261        {
262                set_t *s = set_find( head, set_name );
263                int st;
264               
265                if( s && checkflags && checkflags( irc, s ) == 0 )
266                        return 0;
267               
268                if( del )
269                        st = set_reset( head, set_name );
270                else
271                        st = set_setstr( head, set_name, value );
272               
273                if( set_getstr( head, set_name ) == NULL )
274                {
275                        /* This happens when changing the passwd, for example.
276                           Showing these msgs instead gives slightly clearer
277                           feedback. */
278                        if( st )
279                                irc_usermsg( irc, "Setting changed successfully" );
280                        else
281                                irc_usermsg( irc, "Failed to change setting" );
282                }
283                else
284                {
285                        cmd_showset( irc, head, set_name );
286                }
287        }
288        else if( set_name )
289        {
290                cmd_showset( irc, head, set_name );
291        }
292        else
293        {
294                set_t *s = *head;
295                while( s )
296                {
297                        cmd_showset( irc, &s, s->key );
298                        s = s->next;
299                }
300        }
301       
302        return 1;
303}
304
305static int cmd_account_set_checkflags( irc_t *irc, set_t *s )
306{
307        account_t *a = s->data;
308       
309        if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY )
310        {
311                irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" );
312                return 0;
313        }
314        else if( !a->ic && s && s->flags & ACC_SET_ONLINE_ONLY )
315        {
316                irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" );
317                return 0;
318        }
319       
320        return 1;
321}
322
323static void cmd_account( irc_t *irc, char **cmd )
324{
325        account_t *a;
326       
327        if( global.conf->authmode == AUTHMODE_REGISTERED && !( irc->status & USTATUS_IDENTIFIED ) )
328        {
329                irc_usermsg( irc, "This server only accepts registered users" );
330                return;
331        }
332       
333        if( g_strcasecmp( cmd[1], "add" ) == 0 )
334        {
335                struct prpl *prpl;
336               
337                MIN_ARGS( 4 );
338               
339                prpl = find_protocol( cmd[2] );
340               
341                if( prpl == NULL )
342                {
343                        irc_usermsg( irc, "Unknown protocol" );
344                        return;
345                }
346
347                a = account_add( irc->b, prpl, cmd[3], cmd[4] );
348                if( cmd[5] )
349                {
350                        irc_usermsg( irc, "Warning: Passing a servername/other flags to `account add' "
351                                          "is now deprecated. Use `account set' instead." );
352                        set_setstr( &a->set, "server", cmd[5] );
353                }
354               
355                irc_usermsg( irc, "Account successfully added" );
356               
357                return;
358        }
359        else if( g_strcasecmp( cmd[1], "list" ) == 0 )
360        {
361                int i = 0;
362               
363                if( strchr( irc->umode, 'b' ) )
364                        irc_usermsg( irc, "Account list:" );
365               
366                for( a = irc->b->accounts; a; a = a->next )
367                {
368                        char *con;
369                       
370                        if( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) )
371                                con = " (connected)";
372                        else if( a->ic )
373                                con = " (connecting)";
374                        else if( a->reconnect )
375                                con = " (awaiting reconnect)";
376                        else
377                                con = "";
378                       
379                        irc_usermsg( irc, "%2d. %s, %s%s", i, a->prpl->name, a->user, con );
380                       
381                        i ++;
382                }
383                irc_usermsg( irc, "End of account list" );
384               
385                return;
386        }
387        else if( cmd[2] )
388        {
389                /* Try the following two only if cmd[2] == NULL */
390        }
391        else if( g_strcasecmp( cmd[1], "on" ) == 0 )
392        {
393                if ( irc->b->accounts )
394                {
395                        irc_usermsg( irc, "Trying to get all accounts connected..." );
396               
397                        for( a = irc->b->accounts; a; a = a->next )
398                                if( !a->ic && a->auto_connect )
399                                        account_on( irc->b, a );
400                } 
401                else
402                {
403                        irc_usermsg( irc, "No accounts known. Use `account add' to add one." );
404                }
405               
406                return;
407        }
408        else if( g_strcasecmp( cmd[1], "off" ) == 0 )
409        {
410                irc_usermsg( irc, "Deactivating all active (re)connections..." );
411               
412                for( a = irc->b->accounts; a; a = a->next )
413                {
414                        if( a->ic )
415                                account_off( irc->b, a );
416                        else if( a->reconnect )
417                                cancel_auto_reconnect( a );
418                }
419               
420                return;
421        }
422       
423        MIN_ARGS( 2 );
424       
425        /* At least right now, don't accept on/off/set/del as account IDs even
426           if they're a proper match, since people not familiar with the new
427           syntax yet may get a confusing/nasty surprise. */
428        if( g_strcasecmp( cmd[1], "on" ) == 0 ||
429            g_strcasecmp( cmd[1], "off" ) == 0 ||
430            g_strcasecmp( cmd[1], "set" ) == 0 ||
431            g_strcasecmp( cmd[1], "del" ) == 0 ||
432            ( a = account_get( irc->b, cmd[1] ) ) == NULL )
433        {
434                irc_usermsg( irc, "Could not find account `%s'. Note that the syntax "
435                             "of the account command changed, see \x02help account\x02.", cmd[1] );
436               
437                return;
438        }
439       
440        if( g_strcasecmp( cmd[2], "del" ) == 0 )
441        {
442                if( a->ic )
443                {
444                        irc_usermsg( irc, "Account is still logged in, can't delete" );
445                }
446                else
447                {
448                        account_del( irc->b, a );
449                        irc_usermsg( irc, "Account deleted" );
450                }
451        }
452        else if( g_strcasecmp( cmd[2], "on" ) == 0 )
453        {
454                if( a->ic )
455                        irc_usermsg( irc, "Account already online" );
456                else
457                        account_on( irc->b, a );
458        }
459        else if( g_strcasecmp( cmd[2], "off" ) == 0 )
460        {
461                if( a->ic )
462                {
463                        account_off( irc->b, a );
464                }
465                else if( a->reconnect )
466                {
467                        cancel_auto_reconnect( a );
468                        irc_usermsg( irc, "Reconnect cancelled" );
469                }
470                else
471                {
472                        irc_usermsg( irc, "Account already offline" );
473                }
474        }
475        else if( g_strcasecmp( cmd[2], "set" ) == 0 )
476        {
477                cmd_set_real( irc, cmd + 2, &a->set, cmd_account_set_checkflags );
478        }
479        else
480        {
481                irc_usermsg( irc, "Unknown command: %s [...] %s. Please use \x02help commands\x02 to get a list of available commands.", "account", cmd[2] );
482        }
483}
484
485static void cmd_channel( irc_t *irc, char **cmd )
486{
487        irc_channel_t *ic;
488       
489        if( g_strcasecmp( cmd[1], "list" ) == 0 )
490        {
491                GSList *l;
492                int i = 0;
493               
494                if( strchr( irc->umode, 'b' ) )
495                        irc_usermsg( irc, "Channel list:" );
496               
497                for( l = irc->channels; l; l = l->next )
498                {
499                        irc_channel_t *ic = l->data;
500                       
501                        irc_usermsg( irc, "%2d. %s, %s channel%s", i, ic->name,
502                                     set_getstr( &ic->set, "type" ),
503                                     ic->flags & IRC_CHANNEL_JOINED ? " (joined)" : "" );
504                       
505                        i ++;
506                }
507                irc_usermsg( irc, "End of channel list" );
508               
509                return;
510        }
511       
512        MIN_ARGS( 2 );
513       
514        if( ( ic = irc_channel_get( irc, cmd[1] ) ) == NULL )
515        {
516                irc_usermsg( irc, "Could not find channel `%s'", cmd[1] );
517                return;
518        }
519       
520        if( g_strcasecmp( cmd[2], "set" ) == 0 )
521        {
522                cmd_set_real( irc, cmd + 2, &ic->set, NULL );
523        }
524        else if( g_strcasecmp( cmd[2], "del" ) == 0 )
525        {
526                if( !( ic->flags & IRC_CHANNEL_JOINED ) &&
527                    ic != ic->irc->default_channel )
528                {
529                        irc_usermsg( irc, "Channel %s deleted.", ic->name );
530                        irc_channel_free( ic );
531                }
532                else
533                        irc_usermsg( irc, "Couldn't remove channel (main channel %s or "
534                                          "channels you're still in cannot be deleted).",
535                                          irc->default_channel->name );
536        }
537        else
538        {
539                irc_usermsg( irc, "Unknown command: %s [...] %s. Please use \x02help commands\x02 to get a list of available commands.", "channel", cmd[1] );
540        }
541}
542
543static void cmd_add( irc_t *irc, char **cmd )
544{
545        account_t *a;
546        int add_on_server = 1;
547       
548        if( g_strcasecmp( cmd[1], "-tmp" ) == 0 )
549        {
550                MIN_ARGS( 3 );
551                add_on_server = 0;
552                cmd ++;
553        }
554       
555        if( !( a = account_get( irc->b, cmd[1] ) ) )
556        {
557                irc_usermsg( irc, "Invalid account" );
558                return;
559        }
560        else if( !( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) ) )
561        {
562                irc_usermsg( irc, "That account is not on-line" );
563                return;
564        }
565       
566        if( cmd[3] )
567        {
568                if( !nick_ok( cmd[3] ) )
569                {
570                        irc_usermsg( irc, "The requested nick `%s' is invalid", cmd[3] );
571                        return;
572                }
573                else if( irc_user_by_name( irc, cmd[3] ) )
574                {
575                        irc_usermsg( irc, "The requested nick `%s' already exists", cmd[3] );
576                        return;
577                }
578                else
579                {
580                        nick_set( a, cmd[2], cmd[3] );
581                }
582        }
583       
584        if( add_on_server )
585                a->prpl->add_buddy( a->ic, cmd[2], NULL );
586        else
587                /* Only for add -tmp. For regular adds, this callback will
588                   be called once the IM server confirms. */
589                bee_user_new( irc->b, a->ic, cmd[2], BEE_USER_LOCAL );
590       
591        irc_usermsg( irc, "Adding `%s' to your contact list", cmd[2]  );
592}
593
594static void cmd_remove( irc_t *irc, char **cmd )
595{
596        irc_user_t *iu;
597        bee_user_t *bu;
598        char *s;
599       
600        if( !( iu = irc_user_by_name( irc, cmd[1] ) ) || !( bu = iu->bu ) )
601        {
602                irc_usermsg( irc, "Buddy `%s' not found", cmd[1] );
603                return;
604        }
605        s = g_strdup( bu->handle );
606       
607        bu->ic->acc->prpl->remove_buddy( bu->ic, bu->handle, NULL );
608        nick_del( bu->ic->acc, bu->handle );
609        //TODO(wilmer): bee_user_free() and/or let the IM mod do it? irc_user_free( irc, cmd[1] );
610       
611        irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
612        g_free( s );
613       
614        return;
615}
616
617static void cmd_info( irc_t *irc, char **cmd )
618{
619        struct im_connection *ic;
620        account_t *a;
621       
622        if( !cmd[2] )
623        {
624                irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
625                if( !iu || !iu->bu )
626                {
627                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
628                        return;
629                }
630                ic = iu->bu->ic;
631                cmd[2] = iu->bu->handle;
632        }
633        else if( !( a = account_get( irc->b, cmd[1] ) ) )
634        {
635                irc_usermsg( irc, "Invalid account" );
636                return;
637        }
638        else if( !( ( ic = a->ic ) && ( a->ic->flags & OPT_LOGGED_IN ) ) )
639        {
640                irc_usermsg( irc, "That account is not on-line" );
641                return;
642        }
643       
644        if( !ic->acc->prpl->get_info )
645        {
646                irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
647        }
648        else
649        {
650                ic->acc->prpl->get_info( ic, cmd[2] );
651        }
652}
653
654static void cmd_rename( irc_t *irc, char **cmd )
655{
656        irc_user_t *iu;
657       
658        iu = irc_user_by_name( irc, cmd[1] );
659       
660        if( iu == NULL )
661        {
662                irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
663        }
664        else if( iu == irc->user )
665        {
666                irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] );
667        }
668        else if( !nick_ok( cmd[2] ) )
669        {
670                irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] );
671        }
672        else if( irc_user_by_name( irc, cmd[2] ) )
673        {
674                irc_usermsg( irc, "Nick `%s' already exists", cmd[2] );
675        }
676        else
677        {
678                if( !irc_user_set_nick( iu, cmd[2] ) )
679                {
680                        irc_usermsg( irc, "Error while changing nick" );
681                        return;
682                }
683               
684                if( iu == irc->root )
685                {
686                        /* If we're called internally (user did "set root_nick"),
687                           let's not go O(INF). :-) */
688                        if( strcmp( cmd[0], "set_rename" ) != 0 )
689                                set_setstr( &irc->b->set, "root_nick", cmd[2] );
690                }
691                else if( iu->bu )
692                {
693                        nick_set( iu->bu->ic->acc, iu->bu->handle, cmd[2] );
694                }
695               
696                irc_usermsg( irc, "Nick successfully changed" );
697        }
698}
699
700char *set_eval_root_nick( set_t *set, char *new_nick )
701{
702        irc_t *irc = set->data;
703       
704        if( strcmp( irc->root->nick, new_nick ) != 0 )
705        {
706                char *cmd[] = { "set_rename", irc->root->nick, new_nick, NULL };
707               
708                cmd_rename( irc, cmd );
709        }
710       
711        return strcmp( irc->root->nick, new_nick ) == 0 ? new_nick : SET_INVALID;
712}
713
714static void cmd_block( irc_t *irc, char **cmd )
715{
716        struct im_connection *ic;
717        account_t *a;
718       
719        if( !cmd[2] && ( a = account_get( irc->b, cmd[1] ) ) && a->ic )
720        {
721                char *format;
722                GSList *l;
723               
724                if( strchr( irc->umode, 'b' ) != NULL )
725                        format = "%s\t%s";
726                else
727                        format = "%-32.32s  %-16.16s";
728               
729                irc_usermsg( irc, format, "Handle", "Nickname" );
730                for( l = a->ic->deny; l; l = l->next )
731                {
732                        bee_user_t *bu = bee_user_by_handle( irc->b, a->ic, l->data );
733                        irc_user_t *iu = bu ? bu->ui_data : NULL;
734                        irc_usermsg( irc, format, l->data, iu ? iu->nick : "(none)" );
735                }
736                irc_usermsg( irc, "End of list." );
737               
738                return;
739        }
740        else if( !cmd[2] )
741        {
742                irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
743                if( !iu || !iu->bu )
744                {
745                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
746                        return;
747                }
748                ic = iu->bu->ic;
749                cmd[2] = iu->bu->handle;
750        }
751        else if( !( a = account_get( irc->b, cmd[1] ) ) )
752        {
753                irc_usermsg( irc, "Invalid account" );
754                return;
755        }
756        else if( !( ( ic = a->ic ) && ( a->ic->flags & OPT_LOGGED_IN ) ) )
757        {
758                irc_usermsg( irc, "That account is not on-line" );
759                return;
760        }
761       
762        if( !ic->acc->prpl->add_deny || !ic->acc->prpl->rem_permit )
763        {
764                irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
765        }
766        else
767        {
768                imc_rem_allow( ic, cmd[2] );
769                imc_add_block( ic, cmd[2] );
770                irc_usermsg( irc, "Buddy `%s' moved from your allow- to your block-list", cmd[2] );
771        }
772}
773
774static void cmd_allow( irc_t *irc, char **cmd )
775{
776        struct im_connection *ic;
777        account_t *a;
778       
779        if( !cmd[2] && ( a = account_get( irc->b, cmd[1] ) ) && a->ic )
780        {
781                char *format;
782                GSList *l;
783               
784                if( strchr( irc->umode, 'b' ) != NULL )
785                        format = "%s\t%s";
786                else
787                        format = "%-32.32s  %-16.16s";
788               
789                irc_usermsg( irc, format, "Handle", "Nickname" );
790                for( l = a->ic->permit; l; l = l->next )
791                {
792                        bee_user_t *bu = bee_user_by_handle( irc->b, a->ic, l->data );
793                        irc_user_t *iu = bu ? bu->ui_data : NULL;
794                        irc_usermsg( irc, format, l->data, iu ? iu->nick : "(none)" );
795                }
796                irc_usermsg( irc, "End of list." );
797               
798                return;
799        }
800        else if( !cmd[2] )
801        {
802                irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
803                if( !iu || !iu->bu )
804                {
805                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
806                        return;
807                }
808                ic = iu->bu->ic;
809                cmd[2] = iu->bu->handle;
810        }
811        else if( !( a = account_get( irc->b, cmd[1] ) ) )
812        {
813                irc_usermsg( irc, "Invalid account" );
814                return;
815        }
816        else if( !( ( ic = a->ic ) && ( a->ic->flags & OPT_LOGGED_IN ) ) )
817        {
818                irc_usermsg( irc, "That account is not on-line" );
819                return;
820        }
821       
822        if( !ic->acc->prpl->rem_deny || !ic->acc->prpl->add_permit )
823        {
824                irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
825        }
826        else
827        {
828                imc_rem_block( ic, cmd[2] );
829                imc_add_allow( ic, cmd[2] );
830               
831                irc_usermsg( irc, "Buddy `%s' moved from your block- to your allow-list", cmd[2] );
832        }
833}
834
835static void cmd_yesno( irc_t *irc, char **cmd )
836{
837        query_t *q = NULL;
838        int numq = 0;
839       
840        if( irc->queries == NULL )
841        {
842                irc_usermsg( irc, "Did I ask you something?" );
843                return;
844        }
845       
846        /* If there's an argument, the user seems to want to answer another question than the
847           first/last (depending on the query_order setting) one. */
848        if( cmd[1] )
849        {
850                if( sscanf( cmd[1], "%d", &numq ) != 1 )
851                {
852                        irc_usermsg( irc, "Invalid query number" );
853                        return;
854                }
855               
856                for( q = irc->queries; q; q = q->next, numq -- )
857                        if( numq == 0 )
858                                break;
859               
860                if( !q )
861                {
862                        irc_usermsg( irc, "Uhm, I never asked you something like that..." );
863                        return;
864                }
865        }
866       
867        if( g_strcasecmp( cmd[0], "yes" ) == 0 )
868                query_answer( irc, q, 1 );
869        else if( g_strcasecmp( cmd[0], "no" ) == 0 )
870                query_answer( irc, q, 0 );
871}
872
873static void cmd_set( irc_t *irc, char **cmd )
874{
875        cmd_set_real( irc, cmd, &irc->b->set, NULL );
876}
877
878static void cmd_blist( irc_t *irc, char **cmd )
879{
880        int online = 0, away = 0, offline = 0;
881        GSList *l;
882        char s[256];
883        char *format;
884        int n_online = 0, n_away = 0, n_offline = 0;
885       
886        if( cmd[1] && g_strcasecmp( cmd[1], "all" ) == 0 )
887                online = offline = away = 1;
888        else if( cmd[1] && g_strcasecmp( cmd[1], "offline" ) == 0 )
889                offline = 1;
890        else if( cmd[1] && g_strcasecmp( cmd[1], "away" ) == 0 )
891                away = 1;
892        else if( cmd[1] && g_strcasecmp( cmd[1], "online" ) == 0 )
893                online = 1;
894        else
895                online = away = 1;
896       
897        if( strchr( irc->umode, 'b' ) != NULL )
898                format = "%s\t%s\t%s";
899        else
900                format = "%-16.16s  %-40.40s  %s";
901       
902        irc_usermsg( irc, format, "Nick", "Handle/Account", "Status" );
903       
904        for( l = irc->users; l; l = l->next )
905        {
906                irc_user_t *iu = l->data;
907                bee_user_t *bu = iu->bu;
908               
909                if( !bu || ( bu->flags & ( BEE_USER_ONLINE | BEE_USER_AWAY ) ) != BEE_USER_ONLINE )
910                        continue;
911               
912                if( online == 1 )
913                {
914                        char st[256] = "Online";
915                       
916                        if( bu->status_msg )
917                                g_snprintf( st, sizeof( st ) - 1, "Online (%s)", bu->status_msg );
918                       
919                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
920                        irc_usermsg( irc, format, iu->nick, s, st );
921                }
922               
923                n_online ++;
924        }
925
926        for( l = irc->users; l; l = l->next )
927        {
928                irc_user_t *iu = l->data;
929                bee_user_t *bu = iu->bu;
930               
931                if( !bu || !( bu->flags & BEE_USER_ONLINE ) || !( bu->flags & BEE_USER_AWAY ) )
932                        continue;
933               
934                if( away == 1 )
935                {
936                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
937                        irc_usermsg( irc, format, iu->nick, s, irc_user_get_away( iu ) );
938                }
939                n_away ++;
940        }
941       
942        for( l = irc->users; l; l = l->next )
943        {
944                irc_user_t *iu = l->data;
945                bee_user_t *bu = iu->bu;
946               
947                if( !bu || bu->flags & BEE_USER_ONLINE )
948                        continue;
949               
950                if( offline == 1 )
951                {
952                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
953                        irc_usermsg( irc, format, iu->nick, s, "Offline" );
954                }
955                n_offline ++;
956        }
957       
958        irc_usermsg( irc, "%d buddies (%d available, %d away, %d offline)", n_online + n_away + n_offline, n_online, n_away, n_offline );
959}
960
961static void cmd_qlist( irc_t *irc, char **cmd )
962{
963        query_t *q = irc->queries;
964        int num;
965       
966        if( !q )
967        {
968                irc_usermsg( irc, "There are no pending questions." );
969                return;
970        }
971       
972        irc_usermsg( irc, "Pending queries:" );
973       
974        for( num = 0; q; q = q->next, num ++ )
975                if( q->ic ) /* Not necessary yet, but it might come later */
976                        irc_usermsg( irc, "%d, %s(%s): %s", num, q->ic->acc->prpl->name, q->ic->acc->user, q->question );
977                else
978                        irc_usermsg( irc, "%d, BitlBee: %s", num, q->question );
979}
980
981static void cmd_chat( irc_t *irc, char **cmd )
982{
983        account_t *acc;
984       
985        if( g_strcasecmp( cmd[1], "add" ) == 0 )
986        {
987                char *channel, *s;
988                struct irc_channel *ic;
989               
990                MIN_ARGS( 3 );
991               
992                if( !( acc = account_get( irc->b, cmd[2] ) ) )
993                {
994                        irc_usermsg( irc, "Invalid account" );
995                        return;
996                }
997                else if( !acc->prpl->chat_join )
998                {
999                        irc_usermsg( irc, "Named chatrooms not supported on that account." );
1000                        return;
1001                }
1002               
1003                if( cmd[4] == NULL )
1004                {
1005                        channel = g_strdup( cmd[3] );
1006                        if( ( s = strchr( channel, '@' ) ) )
1007                                *s = 0;
1008                }
1009                else
1010                {
1011                        channel = g_strdup( cmd[4] );
1012                }
1013               
1014                if( strchr( CTYPES, channel[0] ) == NULL )
1015                {
1016                        s = g_strdup_printf( "#%s", channel );
1017                        g_free( channel );
1018                        channel = s;
1019                }
1020               
1021                if( ( ic = irc_channel_new( irc, channel ) ) &&
1022                    set_setstr( &ic->set, "chat_type", "room" ) &&
1023                    set_setstr( &ic->set, "account", cmd[2] ) &&
1024                    set_setstr( &ic->set, "room", cmd[3] ) )
1025                {
1026                        irc_usermsg( irc, "Chatroom successfully added." );
1027                }
1028                else
1029                {
1030                        if( ic )
1031                                irc_channel_free( ic );
1032                       
1033                        irc_usermsg( irc, "Could not add chatroom." );
1034                }
1035                g_free( channel );
1036        }
1037        else if( g_strcasecmp( cmd[1], "with" ) == 0 )
1038        {
1039                irc_user_t *iu;
1040               
1041                MIN_ARGS( 2 );
1042               
1043                if( ( iu = irc_user_by_name( irc, cmd[2] ) ) &&
1044                    iu->bu && iu->bu->ic->acc->prpl->chat_with )
1045                {
1046                        if( !iu->bu->ic->acc->prpl->chat_with( iu->bu->ic, iu->bu->handle ) )
1047                        {
1048                                irc_usermsg( irc, "(Possible) failure while trying to open "
1049                                                  "a groupchat with %s.", iu->nick );
1050                        }
1051                }
1052                else
1053                {
1054                        irc_usermsg( irc, "Can't open a groupchat with %s.", cmd[2] );
1055                }
1056        }
1057        else if( g_strcasecmp( cmd[1], "list" ) == 0 ||
1058                 g_strcasecmp( cmd[1], "set" ) == 0 ||
1059                 g_strcasecmp( cmd[1], "del" ) == 0 )
1060        {
1061                irc_usermsg( irc, "Warning: The \002chat\002 command was mostly replaced with the \002channel\002 command." );
1062                cmd_channel( irc, cmd );
1063        }
1064        else
1065        {
1066                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "chat", cmd[1] );
1067        }
1068}
1069
1070static void cmd_transfer( irc_t *irc, char **cmd )
1071{
1072        GSList *files = irc->file_transfers;
1073        enum { LIST, REJECT, CANCEL };
1074        int subcmd = LIST;
1075        int fid;
1076
1077        if( !files )
1078        {
1079                irc_usermsg( irc, "No pending transfers" );
1080                return;
1081        }
1082
1083        if( cmd[1] && ( strcmp( cmd[1], "reject" ) == 0 ) )
1084        {
1085                subcmd = REJECT;
1086        }
1087        else if( cmd[1] && ( strcmp( cmd[1], "cancel" ) == 0 ) && 
1088                 cmd[2] && ( sscanf( cmd[2], "%d", &fid ) == 1 ) )
1089        {
1090                subcmd = CANCEL;
1091        }
1092
1093        for( ; files; files = g_slist_next( files ) )
1094        {
1095                file_transfer_t *file = files->data;
1096               
1097                switch( subcmd ) {
1098                case LIST:
1099                        if ( file->status == FT_STATUS_LISTENING )
1100                                irc_usermsg( irc, 
1101                                        "Pending file(id %d): %s (Listening...)", file->local_id, file->file_name);
1102                        else 
1103                        {
1104                                int kb_per_s = 0;
1105                                time_t diff = time( NULL ) - file->started ? : 1;
1106                                if ( ( file->started > 0 ) && ( file->bytes_transferred > 0 ) )
1107                                        kb_per_s = file->bytes_transferred / 1024 / diff;
1108                                       
1109                                irc_usermsg( irc, 
1110                                        "Pending file(id %d): %s (%10zd/%zd kb, %d kb/s)", file->local_id, file->file_name, 
1111                                        file->bytes_transferred/1024, file->file_size/1024, kb_per_s);
1112                        }
1113                        break;
1114                case REJECT:
1115                        if( file->status == FT_STATUS_LISTENING )
1116                        {
1117                                irc_usermsg( irc, "Rejecting file transfer for %s", file->file_name );
1118                                imcb_file_canceled( file->ic, file, "Denied by user" );
1119                        }
1120                        break;
1121                case CANCEL:
1122                        if( file->local_id == fid )
1123                        {
1124                                irc_usermsg( irc, "Canceling file transfer for %s", file->file_name );
1125                                imcb_file_canceled( file->ic, file, "Canceled by user" );
1126                        }
1127                        break;
1128                }
1129        }
1130}
1131
1132/* IMPORTANT: Keep this list sorted! The short command logic needs that. */
1133const command_t commands[] = {
1134        { "account",        1, cmd_account,        0 },
1135        { "add",            2, cmd_add,            0 },
1136        { "allow",          1, cmd_allow,          0 },
1137        { "blist",          0, cmd_blist,          0 },
1138        { "block",          1, cmd_block,          0 },
1139        { "channel",        1, cmd_channel,        0 },
1140        { "chat",           1, cmd_chat,           0 },
1141        { "drop",           1, cmd_drop,           0 },
1142        { "ft",             0, cmd_transfer,       0 },
1143        { "help",           0, cmd_help,           0 }, 
1144        { "identify",       1, cmd_identify,       0 },
1145        { "info",           1, cmd_info,           0 },
1146        { "no",             0, cmd_yesno,          0 },
1147        { "qlist",          0, cmd_qlist,          0 },
1148        { "register",       1, cmd_register,       0 },
1149        { "remove",         1, cmd_remove,         0 },
1150        { "rename",         2, cmd_rename,         0 },
1151        { "save",           0, cmd_save,           0 },
1152        { "set",            0, cmd_set,            0 },
1153        { "transfer",       0, cmd_transfer,       0 },
1154        { "yes",            0, cmd_yesno,          0 },
1155        { NULL }
1156};
Note: See TracBrowser for help on using the repository browser.