source: root_commands.c @ acd7959

Last change on this file since acd7959 was acd7959, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-19T12:21:22Z

Forgot one NULL pointer check in the channel sensitivity code for the blist
command.

  • Property mode set to 100644
File size: 31.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( ( ic = irc->root->last_channel ) &&
563                    ( len = strlen( cmd[1] ) ) &&
564                    g_strncasecmp( cmd[1], "set", len ) == 0 )
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->root->last_channel ) &&
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                /* Alright, alright, let's add a tiny easter egg here. */
920                static irc_t *last_irc = NULL;
921                static time_t last_time = 0;
922                static int times = 0;
923                static const char *msg[] = {
924                        "Oh yeah, that's right.",
925                        "Alright, alright. Now go back to work.",
926                        "Buuuuuuuuuuuuuuuurp... Excuse me!",
927                        "Yes?",
928                        "No?",
929                };
930               
931                if( last_irc == irc && time( NULL ) - last_time < 15 )
932                {
933                        if( ( ++times >= 3 ) )
934                        {
935                                irc_usermsg( irc, "%s", msg[rand()%(sizeof(msg)/sizeof(char*))] );
936                                last_irc = NULL;
937                                times = 0;
938                                return;
939                        }
940                }
941                else
942                {
943                        last_time = time( NULL );
944                        last_irc = irc;
945                        times = 0;
946                }
947               
948                irc_usermsg( irc, "Did I ask you something?" );
949                return;
950        }
951       
952        /* If there's an argument, the user seems to want to answer another question than the
953           first/last (depending on the query_order setting) one. */
954        if( cmd[1] )
955        {
956                if( sscanf( cmd[1], "%d", &numq ) != 1 )
957                {
958                        irc_usermsg( irc, "Invalid query number" );
959                        return;
960                }
961               
962                for( q = irc->queries; q; q = q->next, numq -- )
963                        if( numq == 0 )
964                                break;
965               
966                if( !q )
967                {
968                        irc_usermsg( irc, "Uhm, I never asked you something like that..." );
969                        return;
970                }
971        }
972       
973        if( g_strcasecmp( cmd[0], "yes" ) == 0 )
974                query_answer( irc, q, 1 );
975        else if( g_strcasecmp( cmd[0], "no" ) == 0 )
976                query_answer( irc, q, 0 );
977}
978
979static void cmd_set( irc_t *irc, char **cmd )
980{
981        cmd_set_real( irc, cmd, &irc->b->set, NULL );
982}
983
984static void cmd_blist( irc_t *irc, char **cmd )
985{
986        int online = 0, away = 0, offline = 0;
987        GSList *l;
988        char s[256];
989        char *format;
990        int n_online = 0, n_away = 0, n_offline = 0;
991       
992        if( cmd[1] && g_strcasecmp( cmd[1], "all" ) == 0 )
993                online = offline = away = 1;
994        else if( cmd[1] && g_strcasecmp( cmd[1], "offline" ) == 0 )
995                offline = 1;
996        else if( cmd[1] && g_strcasecmp( cmd[1], "away" ) == 0 )
997                away = 1;
998        else if( cmd[1] && g_strcasecmp( cmd[1], "online" ) == 0 )
999                online = 1;
1000        else
1001                online = away = 1;
1002       
1003        if( strchr( irc->umode, 'b' ) != NULL )
1004                format = "%s\t%s\t%s";
1005        else
1006                format = "%-16.16s  %-40.40s  %s";
1007       
1008        irc_usermsg( irc, format, "Nick", "Handle/Account", "Status" );
1009       
1010        if( irc->root->last_channel &&
1011            strcmp( set_getstr( &irc->root->last_channel->set, "type" ), "control" ) != 0 )
1012                irc->root->last_channel = NULL;
1013       
1014        for( l = irc->users; l; l = l->next )
1015        {
1016                irc_user_t *iu = l->data;
1017                bee_user_t *bu = iu->bu;
1018               
1019                if( !bu || ( irc->root->last_channel && !irc_channel_wants_user( irc->root->last_channel, iu ) ) ||
1020                    ( bu->flags & ( BEE_USER_ONLINE | BEE_USER_AWAY ) ) != BEE_USER_ONLINE )
1021                        continue;
1022               
1023                if( online == 1 )
1024                {
1025                        char st[256] = "Online";
1026                       
1027                        if( bu->status_msg )
1028                                g_snprintf( st, sizeof( st ) - 1, "Online (%s)", bu->status_msg );
1029                       
1030                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
1031                        irc_usermsg( irc, format, iu->nick, s, st );
1032                }
1033               
1034                n_online ++;
1035        }
1036
1037        for( l = irc->users; l; l = l->next )
1038        {
1039                irc_user_t *iu = l->data;
1040                bee_user_t *bu = iu->bu;
1041               
1042                if( !bu || ( irc->root->last_channel && !irc_channel_wants_user( irc->root->last_channel, iu ) ) ||
1043                    !( bu->flags & BEE_USER_ONLINE ) || !( bu->flags & BEE_USER_AWAY ) )
1044                        continue;
1045               
1046                if( away == 1 )
1047                {
1048                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
1049                        irc_usermsg( irc, format, iu->nick, s, irc_user_get_away( iu ) );
1050                }
1051                n_away ++;
1052        }
1053       
1054        for( l = irc->users; l; l = l->next )
1055        {
1056                irc_user_t *iu = l->data;
1057                bee_user_t *bu = iu->bu;
1058               
1059                if( !bu || ( irc->root->last_channel && !irc_channel_wants_user( irc->root->last_channel, iu ) ) ||
1060                    bu->flags & BEE_USER_ONLINE )
1061                        continue;
1062               
1063                if( offline == 1 )
1064                {
1065                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
1066                        irc_usermsg( irc, format, iu->nick, s, "Offline" );
1067                }
1068                n_offline ++;
1069        }
1070       
1071        irc_usermsg( irc, "%d buddies (%d available, %d away, %d offline)", n_online + n_away + n_offline, n_online, n_away, n_offline );
1072}
1073
1074static void cmd_qlist( irc_t *irc, char **cmd )
1075{
1076        query_t *q = irc->queries;
1077        int num;
1078       
1079        if( !q )
1080        {
1081                irc_usermsg( irc, "There are no pending questions." );
1082                return;
1083        }
1084       
1085        irc_usermsg( irc, "Pending queries:" );
1086       
1087        for( num = 0; q; q = q->next, num ++ )
1088                if( q->ic ) /* Not necessary yet, but it might come later */
1089                        irc_usermsg( irc, "%d, %s(%s): %s", num, q->ic->acc->prpl->name, q->ic->acc->user, q->question );
1090                else
1091                        irc_usermsg( irc, "%d, BitlBee: %s", num, q->question );
1092}
1093
1094static void cmd_chat( irc_t *irc, char **cmd )
1095{
1096        account_t *acc;
1097       
1098        if( g_strcasecmp( cmd[1], "add" ) == 0 )
1099        {
1100                char *channel, *s;
1101                struct irc_channel *ic;
1102               
1103                MIN_ARGS( 3 );
1104               
1105                if( !( acc = account_get( irc->b, cmd[2] ) ) )
1106                {
1107                        irc_usermsg( irc, "Invalid account" );
1108                        return;
1109                }
1110                else if( !acc->prpl->chat_join )
1111                {
1112                        irc_usermsg( irc, "Named chatrooms not supported on that account." );
1113                        return;
1114                }
1115               
1116                if( cmd[4] == NULL )
1117                {
1118                        channel = g_strdup( cmd[3] );
1119                        if( ( s = strchr( channel, '@' ) ) )
1120                                *s = 0;
1121                }
1122                else
1123                {
1124                        channel = g_strdup( cmd[4] );
1125                }
1126               
1127                if( strchr( CTYPES, channel[0] ) == NULL )
1128                {
1129                        s = g_strdup_printf( "#%s", channel );
1130                        g_free( channel );
1131                        channel = s;
1132                       
1133                        irc_channel_name_strip( channel );
1134                }
1135               
1136                if( ( ic = irc_channel_new( irc, channel ) ) &&
1137                    set_setstr( &ic->set, "type", "chat" ) &&
1138                    set_setstr( &ic->set, "chat_type", "room" ) &&
1139                    set_setstr( &ic->set, "account", cmd[2] ) &&
1140                    set_setstr( &ic->set, "room", cmd[3] ) )
1141                {
1142                        irc_usermsg( irc, "Chatroom successfully added." );
1143                }
1144                else
1145                {
1146                        if( ic )
1147                                irc_channel_free( ic );
1148                       
1149                        irc_usermsg( irc, "Could not add chatroom." );
1150                }
1151                g_free( channel );
1152        }
1153        else if( g_strcasecmp( cmd[1], "with" ) == 0 )
1154        {
1155                irc_user_t *iu;
1156               
1157                MIN_ARGS( 2 );
1158               
1159                if( ( iu = irc_user_by_name( irc, cmd[2] ) ) &&
1160                    iu->bu && iu->bu->ic->acc->prpl->chat_with )
1161                {
1162                        if( !iu->bu->ic->acc->prpl->chat_with( iu->bu->ic, iu->bu->handle ) )
1163                        {
1164                                irc_usermsg( irc, "(Possible) failure while trying to open "
1165                                                  "a groupchat with %s.", iu->nick );
1166                        }
1167                }
1168                else
1169                {
1170                        irc_usermsg( irc, "Can't open a groupchat with %s.", cmd[2] );
1171                }
1172        }
1173        else if( g_strcasecmp( cmd[1], "list" ) == 0 ||
1174                 g_strcasecmp( cmd[1], "set" ) == 0 ||
1175                 g_strcasecmp( cmd[1], "del" ) == 0 )
1176        {
1177                irc_usermsg( irc, "Warning: The \002chat\002 command was mostly replaced with the \002channel\002 command." );
1178                cmd_channel( irc, cmd );
1179        }
1180        else
1181        {
1182                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "chat", cmd[1] );
1183        }
1184}
1185
1186static void cmd_group( irc_t *irc, char **cmd )
1187{
1188        GSList *l;
1189        int len;
1190       
1191        len = strlen( cmd[1] );
1192        if( g_strncasecmp( cmd[1], "list", len ) == 0 )
1193        {
1194                int n = 0;
1195               
1196                if( strchr( irc->umode, 'b' ) )
1197                        irc_usermsg( irc, "Group list:" );
1198               
1199                for( l = irc->b->groups; l; l = l->next )
1200                {
1201                        bee_group_t *bg = l->data;
1202                        irc_usermsg( irc, "%d. %s", n ++, bg->name );
1203                }
1204                irc_usermsg( irc, "End of group list" );
1205        }
1206        else
1207        {
1208                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "group", cmd[1] );
1209        }
1210}
1211
1212static void cmd_transfer( irc_t *irc, char **cmd )
1213{
1214        GSList *files = irc->file_transfers;
1215        enum { LIST, REJECT, CANCEL };
1216        int subcmd = LIST;
1217        int fid;
1218
1219        if( !files )
1220        {
1221                irc_usermsg( irc, "No pending transfers" );
1222                return;
1223        }
1224
1225        if( cmd[1] && ( strcmp( cmd[1], "reject" ) == 0 ) )
1226        {
1227                subcmd = REJECT;
1228        }
1229        else if( cmd[1] && ( strcmp( cmd[1], "cancel" ) == 0 ) && 
1230                 cmd[2] && ( sscanf( cmd[2], "%d", &fid ) == 1 ) )
1231        {
1232                subcmd = CANCEL;
1233        }
1234
1235        for( ; files; files = g_slist_next( files ) )
1236        {
1237                file_transfer_t *file = files->data;
1238               
1239                switch( subcmd ) {
1240                case LIST:
1241                        if ( file->status == FT_STATUS_LISTENING )
1242                                irc_usermsg( irc, 
1243                                        "Pending file(id %d): %s (Listening...)", file->local_id, file->file_name);
1244                        else 
1245                        {
1246                                int kb_per_s = 0;
1247                                time_t diff = time( NULL ) - file->started ? : 1;
1248                                if ( ( file->started > 0 ) && ( file->bytes_transferred > 0 ) )
1249                                        kb_per_s = file->bytes_transferred / 1024 / diff;
1250                                       
1251                                irc_usermsg( irc, 
1252                                        "Pending file(id %d): %s (%10zd/%zd kb, %d kb/s)", file->local_id, file->file_name, 
1253                                        file->bytes_transferred/1024, file->file_size/1024, kb_per_s);
1254                        }
1255                        break;
1256                case REJECT:
1257                        if( file->status == FT_STATUS_LISTENING )
1258                        {
1259                                irc_usermsg( irc, "Rejecting file transfer for %s", file->file_name );
1260                                imcb_file_canceled( file->ic, file, "Denied by user" );
1261                        }
1262                        break;
1263                case CANCEL:
1264                        if( file->local_id == fid )
1265                        {
1266                                irc_usermsg( irc, "Canceling file transfer for %s", file->file_name );
1267                                imcb_file_canceled( file->ic, file, "Canceled by user" );
1268                        }
1269                        break;
1270                }
1271        }
1272}
1273
1274/* IMPORTANT: Keep this list sorted! The short command logic needs that. */
1275const command_t commands[] = {
1276        { "account",        1, cmd_account,        0 },
1277        { "add",            2, cmd_add,            0 },
1278        { "allow",          1, cmd_allow,          0 },
1279        { "blist",          0, cmd_blist,          0 },
1280        { "block",          1, cmd_block,          0 },
1281        { "channel",        1, cmd_channel,        0 },
1282        { "chat",           1, cmd_chat,           0 },
1283        { "drop",           1, cmd_drop,           0 },
1284        { "ft",             0, cmd_transfer,       0 },
1285        { "group",          1, cmd_group,          0 },
1286        { "help",           0, cmd_help,           0 }, 
1287        { "identify",       1, cmd_identify,       0 },
1288        { "info",           1, cmd_info,           0 },
1289        { "no",             0, cmd_yesno,          0 },
1290        { "qlist",          0, cmd_qlist,          0 },
1291        { "register",       1, cmd_register,       0 },
1292        { "remove",         1, cmd_remove,         0 },
1293        { "rename",         2, cmd_rename,         0 },
1294        { "save",           0, cmd_save,           0 },
1295        { "set",            0, cmd_set,            0 },
1296        { "transfer",       0, cmd_transfer,       0 },
1297        { "yes",            0, cmd_yesno,          0 },
1298        { NULL }
1299};
Note: See TracBrowser for help on using the repository browser.