source: root_commands.c @ 4f22a68

Last change on this file since 4f22a68 was 4f22a68, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-18T20:12:55Z

Automatically operate on the current channel if just using "channel set".

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