source: root_commands.c @ 762d96f

Last change on this file since 762d96f was ac2717b, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-08-14T10:55:20Z

blist should only show contacts that are (or would be if they were online)
in the current channel.

  • 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( strcmp( set_getstr( &irc->root->last_channel->set, "type" ), "control" ) != 0 )
1011                irc->root->last_channel = NULL;
1012       
1013        for( l = irc->users; l; l = l->next )
1014        {
1015                irc_user_t *iu = l->data;
1016                bee_user_t *bu = iu->bu;
1017               
1018                if( !bu || ( irc->root->last_channel && !irc_channel_wants_user( irc->root->last_channel, iu ) ) ||
1019                    ( bu->flags & ( BEE_USER_ONLINE | BEE_USER_AWAY ) ) != BEE_USER_ONLINE )
1020                        continue;
1021               
1022                if( online == 1 )
1023                {
1024                        char st[256] = "Online";
1025                       
1026                        if( bu->status_msg )
1027                                g_snprintf( st, sizeof( st ) - 1, "Online (%s)", bu->status_msg );
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, st );
1031                }
1032               
1033                n_online ++;
1034        }
1035
1036        for( l = irc->users; l; l = l->next )
1037        {
1038                irc_user_t *iu = l->data;
1039                bee_user_t *bu = iu->bu;
1040               
1041                if( !bu || ( irc->root->last_channel && !irc_channel_wants_user( irc->root->last_channel, iu ) ) ||
1042                    !( bu->flags & BEE_USER_ONLINE ) || !( bu->flags & BEE_USER_AWAY ) )
1043                        continue;
1044               
1045                if( away == 1 )
1046                {
1047                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
1048                        irc_usermsg( irc, format, iu->nick, s, irc_user_get_away( iu ) );
1049                }
1050                n_away ++;
1051        }
1052       
1053        for( l = irc->users; l; l = l->next )
1054        {
1055                irc_user_t *iu = l->data;
1056                bee_user_t *bu = iu->bu;
1057               
1058                if( !bu || ( irc->root->last_channel && !irc_channel_wants_user( irc->root->last_channel, iu ) ) ||
1059                    bu->flags & BEE_USER_ONLINE )
1060                        continue;
1061               
1062                if( offline == 1 )
1063                {
1064                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
1065                        irc_usermsg( irc, format, iu->nick, s, "Offline" );
1066                }
1067                n_offline ++;
1068        }
1069       
1070        irc_usermsg( irc, "%d buddies (%d available, %d away, %d offline)", n_online + n_away + n_offline, n_online, n_away, n_offline );
1071}
1072
1073static void cmd_qlist( irc_t *irc, char **cmd )
1074{
1075        query_t *q = irc->queries;
1076        int num;
1077       
1078        if( !q )
1079        {
1080                irc_usermsg( irc, "There are no pending questions." );
1081                return;
1082        }
1083       
1084        irc_usermsg( irc, "Pending queries:" );
1085       
1086        for( num = 0; q; q = q->next, num ++ )
1087                if( q->ic ) /* Not necessary yet, but it might come later */
1088                        irc_usermsg( irc, "%d, %s(%s): %s", num, q->ic->acc->prpl->name, q->ic->acc->user, q->question );
1089                else
1090                        irc_usermsg( irc, "%d, BitlBee: %s", num, q->question );
1091}
1092
1093static void cmd_chat( irc_t *irc, char **cmd )
1094{
1095        account_t *acc;
1096       
1097        if( g_strcasecmp( cmd[1], "add" ) == 0 )
1098        {
1099                char *channel, *s;
1100                struct irc_channel *ic;
1101               
1102                MIN_ARGS( 3 );
1103               
1104                if( !( acc = account_get( irc->b, cmd[2] ) ) )
1105                {
1106                        irc_usermsg( irc, "Invalid account" );
1107                        return;
1108                }
1109                else if( !acc->prpl->chat_join )
1110                {
1111                        irc_usermsg( irc, "Named chatrooms not supported on that account." );
1112                        return;
1113                }
1114               
1115                if( cmd[4] == NULL )
1116                {
1117                        channel = g_strdup( cmd[3] );
1118                        if( ( s = strchr( channel, '@' ) ) )
1119                                *s = 0;
1120                }
1121                else
1122                {
1123                        channel = g_strdup( cmd[4] );
1124                }
1125               
1126                if( strchr( CTYPES, channel[0] ) == NULL )
1127                {
1128                        s = g_strdup_printf( "#%s", channel );
1129                        g_free( channel );
1130                        channel = s;
1131                       
1132                        irc_channel_name_strip( channel );
1133                }
1134               
1135                if( ( ic = irc_channel_new( irc, channel ) ) &&
1136                    set_setstr( &ic->set, "type", "chat" ) &&
1137                    set_setstr( &ic->set, "chat_type", "room" ) &&
1138                    set_setstr( &ic->set, "account", cmd[2] ) &&
1139                    set_setstr( &ic->set, "room", cmd[3] ) )
1140                {
1141                        irc_usermsg( irc, "Chatroom successfully added." );
1142                }
1143                else
1144                {
1145                        if( ic )
1146                                irc_channel_free( ic );
1147                       
1148                        irc_usermsg( irc, "Could not add chatroom." );
1149                }
1150                g_free( channel );
1151        }
1152        else if( g_strcasecmp( cmd[1], "with" ) == 0 )
1153        {
1154                irc_user_t *iu;
1155               
1156                MIN_ARGS( 2 );
1157               
1158                if( ( iu = irc_user_by_name( irc, cmd[2] ) ) &&
1159                    iu->bu && iu->bu->ic->acc->prpl->chat_with )
1160                {
1161                        if( !iu->bu->ic->acc->prpl->chat_with( iu->bu->ic, iu->bu->handle ) )
1162                        {
1163                                irc_usermsg( irc, "(Possible) failure while trying to open "
1164                                                  "a groupchat with %s.", iu->nick );
1165                        }
1166                }
1167                else
1168                {
1169                        irc_usermsg( irc, "Can't open a groupchat with %s.", cmd[2] );
1170                }
1171        }
1172        else if( g_strcasecmp( cmd[1], "list" ) == 0 ||
1173                 g_strcasecmp( cmd[1], "set" ) == 0 ||
1174                 g_strcasecmp( cmd[1], "del" ) == 0 )
1175        {
1176                irc_usermsg( irc, "Warning: The \002chat\002 command was mostly replaced with the \002channel\002 command." );
1177                cmd_channel( irc, cmd );
1178        }
1179        else
1180        {
1181                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "chat", cmd[1] );
1182        }
1183}
1184
1185static void cmd_group( irc_t *irc, char **cmd )
1186{
1187        GSList *l;
1188        int len;
1189       
1190        len = strlen( cmd[1] );
1191        if( g_strncasecmp( cmd[1], "list", len ) == 0 )
1192        {
1193                int n = 0;
1194               
1195                if( strchr( irc->umode, 'b' ) )
1196                        irc_usermsg( irc, "Group list:" );
1197               
1198                for( l = irc->b->groups; l; l = l->next )
1199                {
1200                        bee_group_t *bg = l->data;
1201                        irc_usermsg( irc, "%d. %s", n ++, bg->name );
1202                }
1203                irc_usermsg( irc, "End of group list" );
1204        }
1205        else
1206        {
1207                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "group", cmd[1] );
1208        }
1209}
1210
1211static void cmd_transfer( irc_t *irc, char **cmd )
1212{
1213        GSList *files = irc->file_transfers;
1214        enum { LIST, REJECT, CANCEL };
1215        int subcmd = LIST;
1216        int fid;
1217
1218        if( !files )
1219        {
1220                irc_usermsg( irc, "No pending transfers" );
1221                return;
1222        }
1223
1224        if( cmd[1] && ( strcmp( cmd[1], "reject" ) == 0 ) )
1225        {
1226                subcmd = REJECT;
1227        }
1228        else if( cmd[1] && ( strcmp( cmd[1], "cancel" ) == 0 ) && 
1229                 cmd[2] && ( sscanf( cmd[2], "%d", &fid ) == 1 ) )
1230        {
1231                subcmd = CANCEL;
1232        }
1233
1234        for( ; files; files = g_slist_next( files ) )
1235        {
1236                file_transfer_t *file = files->data;
1237               
1238                switch( subcmd ) {
1239                case LIST:
1240                        if ( file->status == FT_STATUS_LISTENING )
1241                                irc_usermsg( irc, 
1242                                        "Pending file(id %d): %s (Listening...)", file->local_id, file->file_name);
1243                        else 
1244                        {
1245                                int kb_per_s = 0;
1246                                time_t diff = time( NULL ) - file->started ? : 1;
1247                                if ( ( file->started > 0 ) && ( file->bytes_transferred > 0 ) )
1248                                        kb_per_s = file->bytes_transferred / 1024 / diff;
1249                                       
1250                                irc_usermsg( irc, 
1251                                        "Pending file(id %d): %s (%10zd/%zd kb, %d kb/s)", file->local_id, file->file_name, 
1252                                        file->bytes_transferred/1024, file->file_size/1024, kb_per_s);
1253                        }
1254                        break;
1255                case REJECT:
1256                        if( file->status == FT_STATUS_LISTENING )
1257                        {
1258                                irc_usermsg( irc, "Rejecting file transfer for %s", file->file_name );
1259                                imcb_file_canceled( file->ic, file, "Denied by user" );
1260                        }
1261                        break;
1262                case CANCEL:
1263                        if( file->local_id == fid )
1264                        {
1265                                irc_usermsg( irc, "Canceling file transfer for %s", file->file_name );
1266                                imcb_file_canceled( file->ic, file, "Canceled by user" );
1267                        }
1268                        break;
1269                }
1270        }
1271}
1272
1273/* IMPORTANT: Keep this list sorted! The short command logic needs that. */
1274const command_t commands[] = {
1275        { "account",        1, cmd_account,        0 },
1276        { "add",            2, cmd_add,            0 },
1277        { "allow",          1, cmd_allow,          0 },
1278        { "blist",          0, cmd_blist,          0 },
1279        { "block",          1, cmd_block,          0 },
1280        { "channel",        1, cmd_channel,        0 },
1281        { "chat",           1, cmd_chat,           0 },
1282        { "drop",           1, cmd_drop,           0 },
1283        { "ft",             0, cmd_transfer,       0 },
1284        { "group",          1, cmd_group,          0 },
1285        { "help",           0, cmd_help,           0 }, 
1286        { "identify",       1, cmd_identify,       0 },
1287        { "info",           1, cmd_info,           0 },
1288        { "no",             0, cmd_yesno,          0 },
1289        { "qlist",          0, cmd_qlist,          0 },
1290        { "register",       1, cmd_register,       0 },
1291        { "remove",         1, cmd_remove,         0 },
1292        { "rename",         2, cmd_rename,         0 },
1293        { "save",           0, cmd_save,           0 },
1294        { "set",            0, cmd_set,            0 },
1295        { "transfer",       0, cmd_transfer,       0 },
1296        { "yes",            0, cmd_yesno,          0 },
1297        { NULL }
1298};
Note: See TracBrowser for help on using the repository browser.