source: root_commands.c @ fe4f28f

Last change on this file since fe4f28f was fe4f28f, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-07-17T16:11:09Z

Remove the user from default_channel if it has the auto_join setting
disabled.

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