source: root_commands.c @ 4255320

Last change on this file since 4255320 was 593971d, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-24T20:59:41Z

Warn when adding an account twice. People are doing this a lot actually,
and it's unlikely to be intentional.

  • Property mode set to 100644
File size: 30.9 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                for( a = irc->b->accounts; a; a = a->next )
384                        if( a->prpl == prpl && prpl->handle_cmp( a->user, cmd[3] ) == 0 )
385                                irc_usermsg( irc, "Warning: You already have an account with "
386                                             "protocol `%s' and username `%s'. Are you accidentally "
387                                             "trying to add it twice?", prpl->name, cmd[3] );
388               
389                a = account_add( irc->b, prpl, cmd[3], cmd[4] );
390                if( cmd[5] )
391                {
392                        irc_usermsg( irc, "Warning: Passing a servername/other flags to `account add' "
393                                          "is now deprecated. Use `account set' instead." );
394                        set_setstr( &a->set, "server", cmd[5] );
395                }
396               
397                irc_usermsg( irc, "Account successfully added" );
398               
399                return;
400        }
401        else if( len >= 1 && g_strncasecmp( cmd[1], "list", len ) == 0 )
402        {
403                int i = 0;
404               
405                if( strchr( irc->umode, 'b' ) )
406                        irc_usermsg( irc, "Account list:" );
407               
408                for( a = irc->b->accounts; a; a = a->next )
409                {
410                        char *con;
411                       
412                        if( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) )
413                                con = " (connected)";
414                        else if( a->ic )
415                                con = " (connecting)";
416                        else if( a->reconnect )
417                                con = " (awaiting reconnect)";
418                        else
419                                con = "";
420                       
421                        irc_usermsg( irc, "%2d (%s): %s, %s%s", i, a->tag, a->prpl->name, a->user, con );
422                       
423                        i ++;
424                }
425                irc_usermsg( irc, "End of account list" );
426               
427                return;
428        }
429        else if( cmd[2] )
430        {
431                /* Try the following two only if cmd[2] == NULL */
432        }
433        else if( len >= 2 && g_strncasecmp( cmd[1], "on", len ) == 0 )
434        {
435                if ( irc->b->accounts )
436                {
437                        irc_usermsg( irc, "Trying to get all accounts connected..." );
438               
439                        for( a = irc->b->accounts; a; a = a->next )
440                                if( !a->ic && a->auto_connect )
441                                        account_on( irc->b, a );
442                } 
443                else
444                {
445                        irc_usermsg( irc, "No accounts known. Use `account add' to add one." );
446                }
447               
448                return;
449        }
450        else if( len >= 2 && g_strncasecmp( cmd[1], "off", len ) == 0 )
451        {
452                irc_usermsg( irc, "Deactivating all active (re)connections..." );
453               
454                for( a = irc->b->accounts; a; a = a->next )
455                {
456                        if( a->ic )
457                                account_off( irc->b, a );
458                        else if( a->reconnect )
459                                cancel_auto_reconnect( a );
460                }
461               
462                return;
463        }
464       
465        MIN_ARGS( 2 );
466        len = strlen( cmd[2] );
467       
468        /* At least right now, don't accept on/off/set/del as account IDs even
469           if they're a proper match, since people not familiar with the new
470           syntax yet may get a confusing/nasty surprise. */
471        if( g_strcasecmp( cmd[1], "on" ) == 0 ||
472            g_strcasecmp( cmd[1], "off" ) == 0 ||
473            g_strcasecmp( cmd[1], "set" ) == 0 ||
474            g_strcasecmp( cmd[1], "del" ) == 0 ||
475            ( a = account_get( irc->b, cmd[1] ) ) == NULL )
476        {
477                irc_usermsg( irc, "Could not find account `%s'. Note that the syntax "
478                             "of the account command changed, see \x02help account\x02.", cmd[1] );
479               
480                return;
481        }
482       
483        if( len >= 1 && g_strncasecmp( cmd[2], "del", len ) == 0 )
484        {
485                if( a->ic )
486                {
487                        irc_usermsg( irc, "Account is still logged in, can't delete" );
488                }
489                else
490                {
491                        account_del( irc->b, a );
492                        irc_usermsg( irc, "Account deleted" );
493                }
494        }
495        else if( len >= 2 && g_strncasecmp( cmd[2], "on", len ) == 0 )
496        {
497                if( a->ic )
498                        irc_usermsg( irc, "Account already online" );
499                else
500                        account_on( irc->b, a );
501        }
502        else if( len >= 2 && g_strncasecmp( cmd[2], "off", len ) == 0 )
503        {
504                if( a->ic )
505                {
506                        account_off( irc->b, a );
507                }
508                else if( a->reconnect )
509                {
510                        cancel_auto_reconnect( a );
511                        irc_usermsg( irc, "Reconnect cancelled" );
512                }
513                else
514                {
515                        irc_usermsg( irc, "Account already offline" );
516                }
517        }
518        else if( len >= 1 && g_strncasecmp( cmd[2], "set", len ) == 0 )
519        {
520                cmd_set_real( irc, cmd + 2, &a->set, cmd_account_set_checkflags );
521        }
522        else
523        {
524                irc_usermsg( irc, "Unknown command: %s [...] %s. Please use \x02help commands\x02 to get a list of available commands.", "account", cmd[2] );
525        }
526}
527
528static void cmd_channel( irc_t *irc, char **cmd )
529{
530        irc_channel_t *ic;
531        int len;
532       
533        len = strlen( cmd[1] );
534       
535        if( len >= 1 && g_strncasecmp( cmd[1], "list", len ) == 0 )
536        {
537                GSList *l;
538                int i = 0;
539               
540                if( strchr( irc->umode, 'b' ) )
541                        irc_usermsg( irc, "Channel list:" );
542               
543                for( l = irc->channels; l; l = l->next )
544                {
545                        irc_channel_t *ic = l->data;
546                       
547                        irc_usermsg( irc, "%2d. %s, %s channel%s", i, ic->name,
548                                     set_getstr( &ic->set, "type" ),
549                                     ic->flags & IRC_CHANNEL_JOINED ? " (joined)" : "" );
550                       
551                        i ++;
552                }
553                irc_usermsg( irc, "End of channel list" );
554               
555                return;
556        }
557       
558        if( ( ic = irc_channel_get( irc, cmd[1] ) ) == NULL )
559        {
560                /* If this doesn't match any channel, maybe this is the short
561                   syntax (only works when used inside a channel). */
562                if( ( len = strlen( cmd[1] ) ) &&
563                    g_strncasecmp( cmd[1], "set", len ) == 0 &&
564                    ( ic = irc_channel_by_name( irc, irc->last_root_cmd ) ) )
565                        cmd_set_real( irc, cmd + 1, &ic->set, NULL );
566                else
567                        irc_usermsg( irc, "Could not find channel `%s'", cmd[1] );
568               
569                return;
570        }
571       
572        MIN_ARGS( 2 );
573        len = strlen( cmd[2] );
574       
575        if( len >= 1 && g_strncasecmp( cmd[2], "set", len ) == 0 )
576        {
577                cmd_set_real( irc, cmd + 2, &ic->set, NULL );
578        }
579        else if( len >= 1 && g_strncasecmp( cmd[2], "del", len ) == 0 )
580        {
581                if( !( ic->flags & IRC_CHANNEL_JOINED ) &&
582                    ic != ic->irc->default_channel )
583                {
584                        irc_usermsg( irc, "Channel %s deleted.", ic->name );
585                        irc_channel_free( ic );
586                }
587                else
588                        irc_usermsg( irc, "Couldn't remove channel (main channel %s or "
589                                          "channels you're still in cannot be deleted).",
590                                          irc->default_channel->name );
591        }
592        else
593        {
594                irc_usermsg( irc, "Unknown command: %s [...] %s. Please use \x02help commands\x02 to get a list of available commands.", "channel", cmd[1] );
595        }
596}
597
598static void cmd_add( irc_t *irc, char **cmd )
599{
600        account_t *a;
601        int add_on_server = 1;
602       
603        if( g_strcasecmp( cmd[1], "-tmp" ) == 0 )
604        {
605                MIN_ARGS( 3 );
606                add_on_server = 0;
607                cmd ++;
608        }
609       
610        if( !( a = account_get( irc->b, cmd[1] ) ) )
611        {
612                irc_usermsg( irc, "Invalid account" );
613                return;
614        }
615        else if( !( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) ) )
616        {
617                irc_usermsg( irc, "That account is not on-line" );
618                return;
619        }
620       
621        if( cmd[3] )
622        {
623                if( !nick_ok( cmd[3] ) )
624                {
625                        irc_usermsg( irc, "The requested nick `%s' is invalid", cmd[3] );
626                        return;
627                }
628                else if( irc_user_by_name( irc, cmd[3] ) )
629                {
630                        irc_usermsg( irc, "The requested nick `%s' already exists", cmd[3] );
631                        return;
632                }
633                else
634                {
635                        nick_set_raw( a, cmd[2], cmd[3] );
636                }
637        }
638       
639        if( add_on_server )
640        {
641                irc_channel_t *ic;
642                char *s, *group = NULL;;
643               
644                if( ( ic = irc_channel_by_name( irc, irc->last_root_cmd ) ) &&
645                    ( s = set_getstr( &ic->set, "fill_by" ) ) &&
646                    strcmp( s, "group" ) == 0 &&
647                    ( group = set_getstr( &ic->set, "group" ) ) )
648                        irc_usermsg( irc, "Adding `%s' to contact list (group %s)",
649                                     cmd[2], group );
650                else
651                        irc_usermsg( irc, "Adding `%s' to contact list", cmd[2] );
652               
653                a->prpl->add_buddy( a->ic, cmd[2], group );
654        }
655        else
656        {
657                bee_user_t *bu;
658                irc_user_t *iu;
659               
660                /* Only for add -tmp. For regular adds, this callback will
661                   be called once the IM server confirms. */
662                if( ( bu = bee_user_new( irc->b, a->ic, cmd[2], BEE_USER_LOCAL ) ) &&
663                    ( iu = bu->ui_data ) )
664                        irc_usermsg( irc, "Temporarily assigned nickname `%s' "
665                                     "to contact `%s'", iu->nick, cmd[2] );
666        }
667       
668}
669
670static void cmd_remove( irc_t *irc, char **cmd )
671{
672        irc_user_t *iu;
673        bee_user_t *bu;
674        char *s;
675       
676        if( !( iu = irc_user_by_name( irc, cmd[1] ) ) || !( bu = iu->bu ) )
677        {
678                irc_usermsg( irc, "Buddy `%s' not found", cmd[1] );
679                return;
680        }
681        s = g_strdup( bu->handle );
682       
683        bu->ic->acc->prpl->remove_buddy( bu->ic, bu->handle, NULL );
684        nick_del( bu );
685        if( g_slist_find( irc->users, iu ) )
686                bee_user_free( irc->b, bu );
687       
688        irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
689        g_free( s );
690       
691        return;
692}
693
694static void cmd_info( irc_t *irc, char **cmd )
695{
696        struct im_connection *ic;
697        account_t *a;
698       
699        if( !cmd[2] )
700        {
701                irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
702                if( !iu || !iu->bu )
703                {
704                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
705                        return;
706                }
707                ic = iu->bu->ic;
708                cmd[2] = iu->bu->handle;
709        }
710        else if( !( a = account_get( irc->b, cmd[1] ) ) )
711        {
712                irc_usermsg( irc, "Invalid account" );
713                return;
714        }
715        else if( !( ( ic = a->ic ) && ( a->ic->flags & OPT_LOGGED_IN ) ) )
716        {
717                irc_usermsg( irc, "That account is not on-line" );
718                return;
719        }
720       
721        if( !ic->acc->prpl->get_info )
722        {
723                irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
724        }
725        else
726        {
727                ic->acc->prpl->get_info( ic, cmd[2] );
728        }
729}
730
731static void cmd_rename( irc_t *irc, char **cmd )
732{
733        irc_user_t *iu, *old;
734       
735        iu = irc_user_by_name( irc, cmd[1] );
736       
737        if( iu == NULL )
738        {
739                irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
740        }
741        else if( iu == irc->user )
742        {
743                irc_usermsg( irc, "Use /nick to change your own nickname" );
744        }
745        else if( !nick_ok( cmd[2] ) )
746        {
747                irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] );
748        }
749        else if( ( old = irc_user_by_name( irc, cmd[2] ) ) && old != iu )
750        {
751                irc_usermsg( irc, "Nick `%s' already exists", cmd[2] );
752        }
753        else
754        {
755                if( !irc_user_set_nick( iu, cmd[2] ) )
756                {
757                        irc_usermsg( irc, "Error while changing nick" );
758                        return;
759                }
760               
761                if( iu == irc->root )
762                {
763                        /* If we're called internally (user did "set root_nick"),
764                           let's not go O(INF). :-) */
765                        if( strcmp( cmd[0], "set_rename" ) != 0 )
766                                set_setstr( &irc->b->set, "root_nick", cmd[2] );
767                }
768                else if( iu->bu )
769                {
770                        nick_set( iu->bu, cmd[2] );
771                }
772               
773                irc_usermsg( irc, "Nick successfully changed" );
774        }
775}
776
777char *set_eval_root_nick( set_t *set, char *new_nick )
778{
779        irc_t *irc = set->data;
780       
781        if( strcmp( irc->root->nick, new_nick ) != 0 )
782        {
783                char *cmd[] = { "set_rename", irc->root->nick, new_nick, NULL };
784               
785                cmd_rename( irc, cmd );
786        }
787       
788        return strcmp( irc->root->nick, new_nick ) == 0 ? new_nick : SET_INVALID;
789}
790
791static void cmd_block( irc_t *irc, char **cmd )
792{
793        struct im_connection *ic;
794        account_t *a;
795       
796        if( !cmd[2] && ( a = account_get( irc->b, cmd[1] ) ) && a->ic )
797        {
798                char *format;
799                GSList *l;
800               
801                if( strchr( irc->umode, 'b' ) != NULL )
802                        format = "%s\t%s";
803                else
804                        format = "%-32.32s  %-16.16s";
805               
806                irc_usermsg( irc, format, "Handle", "Nickname" );
807                for( l = a->ic->deny; l; l = l->next )
808                {
809                        bee_user_t *bu = bee_user_by_handle( irc->b, a->ic, l->data );
810                        irc_user_t *iu = bu ? bu->ui_data : NULL;
811                        irc_usermsg( irc, format, l->data, iu ? iu->nick : "(none)" );
812                }
813                irc_usermsg( irc, "End of list." );
814               
815                return;
816        }
817        else if( !cmd[2] )
818        {
819                irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
820                if( !iu || !iu->bu )
821                {
822                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
823                        return;
824                }
825                ic = iu->bu->ic;
826                cmd[2] = iu->bu->handle;
827        }
828        else if( !( a = account_get( irc->b, cmd[1] ) ) )
829        {
830                irc_usermsg( irc, "Invalid account" );
831                return;
832        }
833        else if( !( ( ic = a->ic ) && ( a->ic->flags & OPT_LOGGED_IN ) ) )
834        {
835                irc_usermsg( irc, "That account is not on-line" );
836                return;
837        }
838       
839        if( !ic->acc->prpl->add_deny || !ic->acc->prpl->rem_permit )
840        {
841                irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
842        }
843        else
844        {
845                imc_rem_allow( ic, cmd[2] );
846                imc_add_block( ic, cmd[2] );
847                irc_usermsg( irc, "Buddy `%s' moved from allow- to block-list", cmd[2] );
848        }
849}
850
851static void cmd_allow( irc_t *irc, char **cmd )
852{
853        struct im_connection *ic;
854        account_t *a;
855       
856        if( !cmd[2] && ( a = account_get( irc->b, cmd[1] ) ) && a->ic )
857        {
858                char *format;
859                GSList *l;
860               
861                if( strchr( irc->umode, 'b' ) != NULL )
862                        format = "%s\t%s";
863                else
864                        format = "%-32.32s  %-16.16s";
865               
866                irc_usermsg( irc, format, "Handle", "Nickname" );
867                for( l = a->ic->permit; l; l = l->next )
868                {
869                        bee_user_t *bu = bee_user_by_handle( irc->b, a->ic, l->data );
870                        irc_user_t *iu = bu ? bu->ui_data : NULL;
871                        irc_usermsg( irc, format, l->data, iu ? iu->nick : "(none)" );
872                }
873                irc_usermsg( irc, "End of list." );
874               
875                return;
876        }
877        else if( !cmd[2] )
878        {
879                irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
880                if( !iu || !iu->bu )
881                {
882                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
883                        return;
884                }
885                ic = iu->bu->ic;
886                cmd[2] = iu->bu->handle;
887        }
888        else if( !( a = account_get( irc->b, cmd[1] ) ) )
889        {
890                irc_usermsg( irc, "Invalid account" );
891                return;
892        }
893        else if( !( ( ic = a->ic ) && ( a->ic->flags & OPT_LOGGED_IN ) ) )
894        {
895                irc_usermsg( irc, "That account is not on-line" );
896                return;
897        }
898       
899        if( !ic->acc->prpl->rem_deny || !ic->acc->prpl->add_permit )
900        {
901                irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
902        }
903        else
904        {
905                imc_rem_block( ic, cmd[2] );
906                imc_add_allow( ic, cmd[2] );
907               
908                irc_usermsg( irc, "Buddy `%s' moved from block- to allow-list", cmd[2] );
909        }
910}
911
912static void cmd_yesno( irc_t *irc, char **cmd )
913{
914        query_t *q = NULL;
915        int numq = 0;
916       
917        if( irc->queries == NULL )
918        {
919                irc_usermsg( irc, "Did I ask you something?" );
920                return;
921        }
922       
923        /* If there's an argument, the user seems to want to answer another question than the
924           first/last (depending on the query_order setting) one. */
925        if( cmd[1] )
926        {
927                if( sscanf( cmd[1], "%d", &numq ) != 1 )
928                {
929                        irc_usermsg( irc, "Invalid query number" );
930                        return;
931                }
932               
933                for( q = irc->queries; q; q = q->next, numq -- )
934                        if( numq == 0 )
935                                break;
936               
937                if( !q )
938                {
939                        irc_usermsg( irc, "Uhm, I never asked you something like that..." );
940                        return;
941                }
942        }
943       
944        if( g_strcasecmp( cmd[0], "yes" ) == 0 )
945                query_answer( irc, q, 1 );
946        else if( g_strcasecmp( cmd[0], "no" ) == 0 )
947                query_answer( irc, q, 0 );
948}
949
950static void cmd_set( irc_t *irc, char **cmd )
951{
952        cmd_set_real( irc, cmd, &irc->b->set, NULL );
953}
954
955static void cmd_blist( irc_t *irc, char **cmd )
956{
957        int online = 0, away = 0, offline = 0;
958        GSList *l;
959        char s[256];
960        char *format;
961        int n_online = 0, n_away = 0, n_offline = 0;
962       
963        if( cmd[1] && g_strcasecmp( cmd[1], "all" ) == 0 )
964                online = offline = away = 1;
965        else if( cmd[1] && g_strcasecmp( cmd[1], "offline" ) == 0 )
966                offline = 1;
967        else if( cmd[1] && g_strcasecmp( cmd[1], "away" ) == 0 )
968                away = 1;
969        else if( cmd[1] && g_strcasecmp( cmd[1], "online" ) == 0 )
970                online = 1;
971        else
972                online = away = 1;
973       
974        if( strchr( irc->umode, 'b' ) != NULL )
975                format = "%s\t%s\t%s";
976        else
977                format = "%-16.16s  %-40.40s  %s";
978       
979        irc_usermsg( irc, format, "Nick", "Handle/Account", "Status" );
980       
981        for( l = irc->users; l; l = l->next )
982        {
983                irc_user_t *iu = l->data;
984                bee_user_t *bu = iu->bu;
985               
986                if( !bu || ( bu->flags & ( BEE_USER_ONLINE | BEE_USER_AWAY ) ) != BEE_USER_ONLINE )
987                        continue;
988               
989                if( online == 1 )
990                {
991                        char st[256] = "Online";
992                       
993                        if( bu->status_msg )
994                                g_snprintf( st, sizeof( st ) - 1, "Online (%s)", bu->status_msg );
995                       
996                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
997                        irc_usermsg( irc, format, iu->nick, s, st );
998                }
999               
1000                n_online ++;
1001        }
1002
1003        for( l = irc->users; l; l = l->next )
1004        {
1005                irc_user_t *iu = l->data;
1006                bee_user_t *bu = iu->bu;
1007               
1008                if( !bu || !( bu->flags & BEE_USER_ONLINE ) || !( bu->flags & BEE_USER_AWAY ) )
1009                        continue;
1010               
1011                if( away == 1 )
1012                {
1013                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
1014                        irc_usermsg( irc, format, iu->nick, s, irc_user_get_away( iu ) );
1015                }
1016                n_away ++;
1017        }
1018       
1019        for( l = irc->users; l; l = l->next )
1020        {
1021                irc_user_t *iu = l->data;
1022                bee_user_t *bu = iu->bu;
1023               
1024                if( !bu || bu->flags & BEE_USER_ONLINE )
1025                        continue;
1026               
1027                if( offline == 1 )
1028                {
1029                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
1030                        irc_usermsg( irc, format, iu->nick, s, "Offline" );
1031                }
1032                n_offline ++;
1033        }
1034       
1035        irc_usermsg( irc, "%d buddies (%d available, %d away, %d offline)", n_online + n_away + n_offline, n_online, n_away, n_offline );
1036}
1037
1038static void cmd_qlist( irc_t *irc, char **cmd )
1039{
1040        query_t *q = irc->queries;
1041        int num;
1042       
1043        if( !q )
1044        {
1045                irc_usermsg( irc, "There are no pending questions." );
1046                return;
1047        }
1048       
1049        irc_usermsg( irc, "Pending queries:" );
1050       
1051        for( num = 0; q; q = q->next, num ++ )
1052                if( q->ic ) /* Not necessary yet, but it might come later */
1053                        irc_usermsg( irc, "%d, %s(%s): %s", num, q->ic->acc->prpl->name, q->ic->acc->user, q->question );
1054                else
1055                        irc_usermsg( irc, "%d, BitlBee: %s", num, q->question );
1056}
1057
1058static void cmd_chat( irc_t *irc, char **cmd )
1059{
1060        account_t *acc;
1061       
1062        if( g_strcasecmp( cmd[1], "add" ) == 0 )
1063        {
1064                char *channel, *s;
1065                struct irc_channel *ic;
1066               
1067                MIN_ARGS( 3 );
1068               
1069                if( !( acc = account_get( irc->b, cmd[2] ) ) )
1070                {
1071                        irc_usermsg( irc, "Invalid account" );
1072                        return;
1073                }
1074                else if( !acc->prpl->chat_join )
1075                {
1076                        irc_usermsg( irc, "Named chatrooms not supported on that account." );
1077                        return;
1078                }
1079               
1080                if( cmd[4] == NULL )
1081                {
1082                        channel = g_strdup( cmd[3] );
1083                        if( ( s = strchr( channel, '@' ) ) )
1084                                *s = 0;
1085                }
1086                else
1087                {
1088                        channel = g_strdup( cmd[4] );
1089                }
1090               
1091                if( strchr( CTYPES, channel[0] ) == NULL )
1092                {
1093                        s = g_strdup_printf( "#%s", channel );
1094                        g_free( channel );
1095                        channel = s;
1096                       
1097                        irc_channel_name_strip( channel );
1098                }
1099               
1100                if( ( ic = irc_channel_new( irc, channel ) ) &&
1101                    set_setstr( &ic->set, "type", "chat" ) &&
1102                    set_setstr( &ic->set, "chat_type", "room" ) &&
1103                    set_setstr( &ic->set, "account", cmd[2] ) &&
1104                    set_setstr( &ic->set, "room", cmd[3] ) )
1105                {
1106                        irc_usermsg( irc, "Chatroom successfully added." );
1107                }
1108                else
1109                {
1110                        if( ic )
1111                                irc_channel_free( ic );
1112                       
1113                        irc_usermsg( irc, "Could not add chatroom." );
1114                }
1115                g_free( channel );
1116        }
1117        else if( g_strcasecmp( cmd[1], "with" ) == 0 )
1118        {
1119                irc_user_t *iu;
1120               
1121                MIN_ARGS( 2 );
1122               
1123                if( ( iu = irc_user_by_name( irc, cmd[2] ) ) &&
1124                    iu->bu && iu->bu->ic->acc->prpl->chat_with )
1125                {
1126                        if( !iu->bu->ic->acc->prpl->chat_with( iu->bu->ic, iu->bu->handle ) )
1127                        {
1128                                irc_usermsg( irc, "(Possible) failure while trying to open "
1129                                                  "a groupchat with %s.", iu->nick );
1130                        }
1131                }
1132                else
1133                {
1134                        irc_usermsg( irc, "Can't open a groupchat with %s.", cmd[2] );
1135                }
1136        }
1137        else if( g_strcasecmp( cmd[1], "list" ) == 0 ||
1138                 g_strcasecmp( cmd[1], "set" ) == 0 ||
1139                 g_strcasecmp( cmd[1], "del" ) == 0 )
1140        {
1141                irc_usermsg( irc, "Warning: The \002chat\002 command was mostly replaced with the \002channel\002 command." );
1142                cmd_channel( irc, cmd );
1143        }
1144        else
1145        {
1146                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "chat", cmd[1] );
1147        }
1148}
1149
1150static void cmd_group( irc_t *irc, char **cmd )
1151{
1152        GSList *l;
1153        int len;
1154       
1155        len = strlen( cmd[1] );
1156        if( g_strncasecmp( cmd[1], "list", len ) == 0 )
1157        {
1158                int n = 0;
1159               
1160                if( strchr( irc->umode, 'b' ) )
1161                        irc_usermsg( irc, "Group list:" );
1162               
1163                for( l = irc->b->groups; l; l = l->next )
1164                {
1165                        bee_group_t *bg = l->data;
1166                        irc_usermsg( irc, "%d. %s", n ++, bg->name );
1167                }
1168                irc_usermsg( irc, "End of group list" );
1169        }
1170        else
1171        {
1172                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "group", cmd[1] );
1173        }
1174}
1175
1176static void cmd_transfer( irc_t *irc, char **cmd )
1177{
1178        GSList *files = irc->file_transfers;
1179        enum { LIST, REJECT, CANCEL };
1180        int subcmd = LIST;
1181        int fid;
1182
1183        if( !files )
1184        {
1185                irc_usermsg( irc, "No pending transfers" );
1186                return;
1187        }
1188
1189        if( cmd[1] && ( strcmp( cmd[1], "reject" ) == 0 ) )
1190        {
1191                subcmd = REJECT;
1192        }
1193        else if( cmd[1] && ( strcmp( cmd[1], "cancel" ) == 0 ) && 
1194                 cmd[2] && ( sscanf( cmd[2], "%d", &fid ) == 1 ) )
1195        {
1196                subcmd = CANCEL;
1197        }
1198
1199        for( ; files; files = g_slist_next( files ) )
1200        {
1201                file_transfer_t *file = files->data;
1202               
1203                switch( subcmd ) {
1204                case LIST:
1205                        if ( file->status == FT_STATUS_LISTENING )
1206                                irc_usermsg( irc, 
1207                                        "Pending file(id %d): %s (Listening...)", file->local_id, file->file_name);
1208                        else 
1209                        {
1210                                int kb_per_s = 0;
1211                                time_t diff = time( NULL ) - file->started ? : 1;
1212                                if ( ( file->started > 0 ) && ( file->bytes_transferred > 0 ) )
1213                                        kb_per_s = file->bytes_transferred / 1024 / diff;
1214                                       
1215                                irc_usermsg( irc, 
1216                                        "Pending file(id %d): %s (%10zd/%zd kb, %d kb/s)", file->local_id, file->file_name, 
1217                                        file->bytes_transferred/1024, file->file_size/1024, kb_per_s);
1218                        }
1219                        break;
1220                case REJECT:
1221                        if( file->status == FT_STATUS_LISTENING )
1222                        {
1223                                irc_usermsg( irc, "Rejecting file transfer for %s", file->file_name );
1224                                imcb_file_canceled( file->ic, file, "Denied by user" );
1225                        }
1226                        break;
1227                case CANCEL:
1228                        if( file->local_id == fid )
1229                        {
1230                                irc_usermsg( irc, "Canceling file transfer for %s", file->file_name );
1231                                imcb_file_canceled( file->ic, file, "Canceled by user" );
1232                        }
1233                        break;
1234                }
1235        }
1236}
1237
1238/* IMPORTANT: Keep this list sorted! The short command logic needs that. */
1239const command_t commands[] = {
1240        { "account",        1, cmd_account,        0 },
1241        { "add",            2, cmd_add,            0 },
1242        { "allow",          1, cmd_allow,          0 },
1243        { "blist",          0, cmd_blist,          0 },
1244        { "block",          1, cmd_block,          0 },
1245        { "channel",        1, cmd_channel,        0 },
1246        { "chat",           1, cmd_chat,           0 },
1247        { "drop",           1, cmd_drop,           0 },
1248        { "ft",             0, cmd_transfer,       0 },
1249        { "group",          1, cmd_group,          0 },
1250        { "help",           0, cmd_help,           0 }, 
1251        { "identify",       1, cmd_identify,       0 },
1252        { "info",           1, cmd_info,           0 },
1253        { "no",             0, cmd_yesno,          0 },
1254        { "qlist",          0, cmd_qlist,          0 },
1255        { "register",       1, cmd_register,       0 },
1256        { "remove",         1, cmd_remove,         0 },
1257        { "rename",         2, cmd_rename,         0 },
1258        { "save",           0, cmd_save,           0 },
1259        { "set",            0, cmd_set,            0 },
1260        { "transfer",       0, cmd_transfer,       0 },
1261        { "yes",            0, cmd_yesno,          0 },
1262        { NULL }
1263};
Note: See TracBrowser for help on using the repository browser.