2011-02-23 22:14:30 -05:00
/* X-Chat
* Copyright ( C ) 1998 Peter Zelezny .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA
*/
# define _GNU_SOURCE /* for memrchr */
# include <string.h>
# include <stdlib.h>
# include <stdio.h>
# include <ctype.h>
# include <limits.h>
# include <errno.h>
# define WANTSOCKET
# define WANTARPA
# include "inet.h"
# ifndef WIN32
# include <sys/wait.h>
# endif
# include <time.h>
# include <signal.h>
# include <sys/stat.h>
# include <fcntl.h>
# include "xchat.h"
# include "plugin.h"
# include "ignore.h"
# include "util.h"
# include "fe.h"
# include "cfgfiles.h" /* xchat_fopen_file() */
# include "network.h" /* net_ip() */
# include "modes.h"
# include "notify.h"
# include "inbound.h"
# include "text.h"
# include "xchatc.h"
# include "servlist.h"
# include "server.h"
# include "tree.h"
# include "outbound.h"
# ifdef USE_DEBUG
extern int current_mem_usage ;
# endif
# define TBUFSIZE 4096
static void help ( session * sess , char * tbuf , char * helpcmd , int quiet ) ;
static int cmd_server ( session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] ) ;
static void handle_say ( session * sess , char * text , int check_spch ) ;
static void
notj_msg ( struct session * sess )
{
PrintText ( sess , _ ( " No channel joined. Try /join #<channel> \n " ) ) ;
}
void
notc_msg ( struct session * sess )
{
PrintText ( sess , _ ( " Not connected. Try /server <host> [<port>] \n " ) ) ;
}
static char *
random_line ( char * file_name )
{
FILE * fh ;
char buf [ 512 ] ;
int lines , ran ;
if ( ! file_name [ 0 ] )
goto nofile ;
fh = xchat_fopen_file ( file_name , " r " , 0 ) ;
if ( ! fh )
{
nofile :
/* reason is not a file, an actual reason! */
return strdup ( file_name ) ;
}
/* count number of lines in file */
lines = 0 ;
while ( fgets ( buf , sizeof ( buf ) , fh ) )
lines + + ;
if ( lines < 1 )
goto nofile ;
/* go down a random number */
rewind ( fh ) ;
ran = RAND_INT ( lines ) ;
do
{
fgets ( buf , sizeof ( buf ) , fh ) ;
lines - - ;
}
while ( lines > ran ) ;
fclose ( fh ) ;
buf [ strlen ( buf ) - 1 ] = 0 ; /* remove the trailing '\n' */
return strdup ( buf ) ;
}
void
server_sendpart ( server * serv , char * channel , char * reason )
{
if ( ! reason )
{
reason = random_line ( prefs . partreason ) ;
serv - > p_part ( serv , channel , reason ) ;
free ( reason ) ;
} else
{
/* reason set by /quit, /close argument */
serv - > p_part ( serv , channel , reason ) ;
}
}
void
server_sendquit ( session * sess )
{
char * rea , * colrea ;
if ( ! sess - > quitreason )
{
colrea = strdup ( prefs . quitreason ) ;
check_special_chars ( colrea , FALSE ) ;
rea = random_line ( colrea ) ;
free ( colrea ) ;
sess - > server - > p_quit ( sess - > server , rea ) ;
free ( rea ) ;
} else
{
/* reason set by /quit, /close argument */
sess - > server - > p_quit ( sess - > server , sess - > quitreason ) ;
}
}
void
process_data_init ( char * buf , char * cmd , char * word [ ] ,
char * word_eol [ ] , gboolean handle_quotes ,
gboolean allow_escape_quotes )
{
int wordcount = 2 ;
int space = FALSE ;
int quote = FALSE ;
int j = 0 ;
int len ;
word [ 0 ] = " \000 \000 " ;
word_eol [ 0 ] = " \000 \000 " ;
word [ 1 ] = ( char * ) buf ;
word_eol [ 1 ] = ( char * ) cmd ;
while ( 1 )
{
switch ( * cmd )
{
case 0 :
buf [ j ] = 0 ;
for ( j = wordcount ; j < PDIWORDS ; j + + )
{
word [ j ] = " \000 \000 " ;
word_eol [ j ] = " \000 \000 " ;
}
return ;
case ' \042 ' :
if ( ! handle_quotes )
goto def ;
/* two quotes turn into 1 */
if ( allow_escape_quotes & & cmd [ 1 ] = = ' \042 ' )
{
cmd + + ;
goto def ;
}
if ( quote )
{
quote = FALSE ;
space = FALSE ;
} else
quote = TRUE ;
cmd + + ;
break ;
case ' ' :
if ( ! quote )
{
if ( ! space )
{
buf [ j ] = 0 ;
j + + ;
if ( wordcount < PDIWORDS )
{
word [ wordcount ] = & buf [ j ] ;
word_eol [ wordcount ] = cmd + 1 ;
wordcount + + ;
}
space = TRUE ;
}
cmd + + ;
break ;
}
default :
def :
space = FALSE ;
len = g_utf8_skip [ ( ( unsigned char * ) cmd ) [ 0 ] ] ;
if ( len = = 1 )
{
buf [ j ] = * cmd ;
j + + ;
cmd + + ;
} else
{
/* skip past a multi-byte utf8 char */
memcpy ( buf + j , cmd , len ) ;
j + = len ;
cmd + = len ;
}
}
}
}
static int
cmd_addbutton ( struct session * sess , char * tbuf , char * word [ ] ,
char * word_eol [ ] )
{
if ( * word [ 2 ] & & * word_eol [ 3 ] )
{
if ( sess - > type = = SESS_DIALOG )
{
list_addentry ( & dlgbutton_list , word_eol [ 3 ] , word [ 2 ] ) ;
fe_dlgbuttons_update ( sess ) ;
} else
{
list_addentry ( & button_list , word_eol [ 3 ] , word [ 2 ] ) ;
fe_buttons_update ( sess ) ;
}
return TRUE ;
}
return FALSE ;
}
static int
cmd_allchannels ( session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
GSList * list = sess_list ;
if ( ! * word_eol [ 2 ] )
return FALSE ;
while ( list )
{
sess = list - > data ;
if ( sess - > type = = SESS_CHANNEL & & sess - > channel [ 0 ] & & sess - > server - > connected )
{
handle_command ( sess , word_eol [ 2 ] , FALSE ) ;
}
list = list - > next ;
}
return TRUE ;
}
static int
cmd_allchannelslocal ( session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
GSList * list = sess_list ;
server * serv = sess - > server ;
if ( ! * word_eol [ 2 ] )
return FALSE ;
while ( list )
{
sess = list - > data ;
if ( sess - > type = = SESS_CHANNEL & & sess - > channel [ 0 ] & &
sess - > server - > connected & & sess - > server = = serv )
{
handle_command ( sess , word_eol [ 2 ] , FALSE ) ;
}
list = list - > next ;
}
return TRUE ;
}
static int
cmd_allservers ( struct session * sess , char * tbuf , char * word [ ] ,
char * word_eol [ ] )
{
GSList * list ;
server * serv ;
if ( ! * word_eol [ 2 ] )
return FALSE ;
list = serv_list ;
while ( list )
{
serv = list - > data ;
if ( serv - > connected )
handle_command ( serv - > front_session , word_eol [ 2 ] , FALSE ) ;
list = list - > next ;
}
return TRUE ;
}
static int
cmd_away ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
GSList * list ;
char * reason = word_eol [ 2 ] ;
if ( ! ( * reason ) )
{
if ( sess - > server - > is_away )
{
if ( sess - > server - > last_away_reason )
PrintTextf ( sess , _ ( " Already marked away: %s \n " ) , sess - > server - > last_away_reason ) ;
return FALSE ;
}
if ( sess - > server - > reconnect_away )
reason = sess - > server - > last_away_reason ;
else
/* must manage memory pointed to by random_line() */
reason = random_line ( prefs . awayreason ) ;
}
sess - > server - > p_set_away ( sess - > server , reason ) ;
if ( prefs . show_away_message )
{
snprintf ( tbuf , TBUFSIZE , " me is away: %s " , reason ) ;
for ( list = sess_list ; list ; list = list - > next )
{
/* am I the right server and not a dialog box */
if ( ( ( struct session * ) list - > data ) - > server = = sess - > server
& & ( ( struct session * ) list - > data ) - > type = = SESS_CHANNEL
& & ( ( struct session * ) list - > data ) - > channel [ 0 ] )
{
handle_command ( ( session * ) list - > data , tbuf , TRUE ) ;
}
}
}
if ( sess - > server - > last_away_reason ! = reason )
{
if ( sess - > server - > last_away_reason )
free ( sess - > server - > last_away_reason ) ;
if ( reason = = word_eol [ 2 ] )
sess - > server - > last_away_reason = strdup ( reason ) ;
else
sess - > server - > last_away_reason = reason ;
}
if ( ! sess - > server - > connected )
sess - > server - > reconnect_away = 1 ;
return TRUE ;
}
static int
cmd_back ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
GSList * list ;
unsigned int gone ;
if ( sess - > server - > is_away )
{
sess - > server - > p_set_back ( sess - > server ) ;
if ( prefs . show_away_message )
{
gone = time ( NULL ) - sess - > server - > away_time ;
sprintf ( tbuf , " me is back (gone %.2d:%.2d:%.2d) " , gone / 3600 ,
( gone / 60 ) % 60 , gone % 60 ) ;
for ( list = sess_list ; list ; list = list - > next )
{
/* am I the right server and not a dialog box */
if ( ( ( struct session * ) list - > data ) - > server = = sess - > server
& & ( ( struct session * ) list - > data ) - > type = = SESS_CHANNEL
& & ( ( struct session * ) list - > data ) - > channel [ 0 ] )
{
handle_command ( ( session * ) list - > data , tbuf , TRUE ) ;
}
}
}
}
else
{
PrintText ( sess , _ ( " Already marked back. \n " ) ) ;
}
if ( sess - > server - > last_away_reason )
free ( sess - > server - > last_away_reason ) ;
sess - > server - > last_away_reason = NULL ;
return TRUE ;
}
static void
ban ( session * sess , char * tbuf , char * mask , char * bantypestr , int deop )
{
int bantype ;
struct User * user ;
char * at , * dot , * lastdot ;
char username [ 64 ] , fullhost [ 128 ] , domain [ 128 ] , * mode , * p2 ;
server * serv = sess - > server ;
user = userlist_find ( sess , mask ) ;
if ( user & & user - > hostname ) /* it's a nickname, let's find a proper ban mask */
{
if ( deop )
{
mode = " -o+b " ;
p2 = user - > nick ;
} else
{
mode = " +b " ;
p2 = " " ;
}
mask = user - > hostname ;
at = strchr ( mask , ' @ ' ) ; /* FIXME: utf8 */
if ( ! at )
return ; /* can't happen? */
* at = 0 ;
if ( mask [ 0 ] = = ' ~ ' | | mask [ 0 ] = = ' + ' | |
mask [ 0 ] = = ' = ' | | mask [ 0 ] = = ' ^ ' | | mask [ 0 ] = = ' - ' )
{
/* the ident is prefixed with something, we replace that sign with an * */
safe_strcpy ( username + 1 , mask + 1 , sizeof ( username ) - 1 ) ;
username [ 0 ] = ' * ' ;
} else if ( at - mask < USERNAMELEN )
{
/* we just add an * in the begining of the ident */
safe_strcpy ( username + 1 , mask , sizeof ( username ) - 1 ) ;
username [ 0 ] = ' * ' ;
} else
{
/* ident might be too long, we just ban what it gives and add an * in the end */
safe_strcpy ( username , mask , sizeof ( username ) ) ;
}
* at = ' @ ' ;
safe_strcpy ( fullhost , at + 1 , sizeof ( fullhost ) ) ;
dot = strchr ( fullhost , ' . ' ) ;
if ( dot )
{
safe_strcpy ( domain , dot , sizeof ( domain ) ) ;
} else
{
safe_strcpy ( domain , fullhost , sizeof ( domain ) ) ;
}
if ( * bantypestr )
bantype = atoi ( bantypestr ) ;
else
bantype = prefs . bantype ;
tbuf [ 0 ] = 0 ;
if ( inet_addr ( fullhost ) ! = - 1 ) /* "fullhost" is really a IP number */
{
lastdot = strrchr ( fullhost , ' . ' ) ;
if ( ! lastdot )
return ; /* can't happen? */
* lastdot = 0 ;
strcpy ( domain , fullhost ) ;
* lastdot = ' . ' ;
switch ( bantype )
{
case 0 :
snprintf ( tbuf , TBUFSIZE , " %s%s *!*@%s.* " , mode , p2 , domain ) ;
break ;
case 1 :
snprintf ( tbuf , TBUFSIZE , " %s%s *!*@%s " , mode , p2 , fullhost ) ;
break ;
case 2 :
snprintf ( tbuf , TBUFSIZE , " %s%s *!%s@%s.* " , mode , p2 , username , domain ) ;
break ;
case 3 :
snprintf ( tbuf , TBUFSIZE , " %s%s *!%s@%s " , mode , p2 , username , fullhost ) ;
break ;
}
} else
{
switch ( bantype )
{
case 0 :
snprintf ( tbuf , TBUFSIZE , " %s%s *!*@*%s " , mode , p2 , domain ) ;
break ;
case 1 :
snprintf ( tbuf , TBUFSIZE , " %s%s *!*@%s " , mode , p2 , fullhost ) ;
break ;
case 2 :
snprintf ( tbuf , TBUFSIZE , " %s%s *!%s@*%s " , mode , p2 , username , domain ) ;
break ;
case 3 :
snprintf ( tbuf , TBUFSIZE , " %s%s *!%s@%s " , mode , p2 , username , fullhost ) ;
break ;
}
}
} else
{
snprintf ( tbuf , TBUFSIZE , " +b %s " , mask ) ;
}
serv - > p_mode ( serv , sess - > channel , tbuf ) ;
}
static int
cmd_ban ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * mask = word [ 2 ] ;
if ( * mask )
{
ban ( sess , tbuf , mask , word [ 3 ] , 0 ) ;
} else
{
sess - > server - > p_mode ( sess - > server , sess - > channel , " +b " ) ; /* banlist */
}
return TRUE ;
}
static int
cmd_unban ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
/* Allow more than one mask in /unban -- tvk */
int i = 2 ;
while ( 1 )
{
if ( ! * word [ i ] )
{
if ( i = = 2 )
return FALSE ;
send_channel_modes ( sess , tbuf , word , 2 , i , ' - ' , ' b ' , 0 ) ;
return TRUE ;
}
i + + ;
}
}
static int
cmd_chanopt ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
/* chanopt.c */
return chanopt_command ( sess , tbuf , word , word_eol ) ;
}
static int
cmd_charset ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
server * serv = sess - > server ;
const char * locale = NULL ;
int offset = 0 ;
if ( strcmp ( word [ 2 ] , " -quiet " ) = = 0 )
offset + + ;
if ( ! word [ 2 + offset ] [ 0 ] )
{
g_get_charset ( & locale ) ;
PrintTextf ( sess , " Current charset: %s \n " ,
serv - > encoding ? serv - > encoding : locale ) ;
return TRUE ;
}
if ( servlist_check_encoding ( word [ 2 + offset ] ) )
{
server_set_encoding ( serv , word [ 2 + offset ] ) ;
if ( offset < 1 )
PrintTextf ( sess , " Charset changed to: %s \n " , word [ 2 + offset ] ) ;
} else
{
PrintTextf ( sess , " \003 4Unknown charset: \017 %s \n " , word [ 2 + offset ] ) ;
}
return TRUE ;
}
static int
cmd_clear ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
GSList * list = sess_list ;
char * reason = word_eol [ 2 ] ;
if ( strcasecmp ( reason , " HISTORY " ) = = 0 )
{
history_free ( & sess - > history ) ;
return TRUE ;
}
if ( strncasecmp ( reason , " all " , 3 ) = = 0 )
{
while ( list )
{
sess = list - > data ;
if ( ! sess - > nick_said )
fe_text_clear ( list - > data , 0 ) ;
list = list - > next ;
}
return TRUE ;
}
if ( reason [ 0 ] ! = ' - ' & & ! isdigit ( reason [ 0 ] ) & & reason [ 0 ] ! = 0 )
return FALSE ;
fe_text_clear ( sess , atoi ( reason ) ) ;
return TRUE ;
}
static int
cmd_close ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
GSList * list ;
if ( strcmp ( word [ 2 ] , " -m " ) = = 0 )
{
list = sess_list ;
while ( list )
{
sess = list - > data ;
list = list - > next ;
if ( sess - > type = = SESS_DIALOG )
fe_close_window ( sess ) ;
}
} else
{
if ( * word_eol [ 2 ] )
sess - > quitreason = word_eol [ 2 ] ;
fe_close_window ( sess ) ;
}
return TRUE ;
}
static int
cmd_ctcp ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int mbl ;
char * to = word [ 2 ] ;
if ( * to )
{
char * msg = word_eol [ 3 ] ;
if ( * msg )
{
unsigned char * cmd = ( unsigned char * ) msg ;
/* make the first word upper case (as per RFC) */
while ( 1 )
{
if ( * cmd = = ' ' | | * cmd = = 0 )
break ;
mbl = g_utf8_skip [ * cmd ] ;
if ( mbl = = 1 )
* cmd = toupper ( * cmd ) ;
cmd + = mbl ;
}
sess - > server - > p_ctcp ( sess - > server , to , msg ) ;
EMIT_SIGNAL ( XP_TE_CTCPSEND , sess , to , msg , NULL , NULL , 0 ) ;
return TRUE ;
}
}
return FALSE ;
}
static int
cmd_country ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * code = word [ 2 ] ;
if ( * code )
{
/* search? */
if ( strcmp ( code , " -s " ) = = 0 )
{
country_search ( word [ 3 ] , sess , ( void * ) PrintTextf ) ;
return TRUE ;
}
/* search, but forgot the -s */
if ( strchr ( code , ' * ' ) )
{
country_search ( code , sess , ( void * ) PrintTextf ) ;
return TRUE ;
}
sprintf ( tbuf , " %s = %s \n " , code , country ( code ) ) ;
PrintText ( sess , tbuf ) ;
return TRUE ;
}
return FALSE ;
}
static int
cmd_cycle ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * key = sess - > channelkey ;
char * chan = word [ 2 ] ;
if ( ! * chan )
chan = sess - > channel ;
if ( * chan & & sess - > type = = SESS_CHANNEL )
{
sess - > server - > p_cycle ( sess - > server , chan , key ) ;
return TRUE ;
}
return FALSE ;
}
static int
cmd_dcc ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int goodtype ;
struct DCC * dcc = 0 ;
char * type = word [ 2 ] ;
if ( * type )
{
if ( ! strcasecmp ( type , " HELP " ) )
return FALSE ;
if ( ! strcasecmp ( type , " CLOSE " ) )
{
if ( * word [ 3 ] & & * word [ 4 ] )
{
goodtype = 0 ;
if ( ! strcasecmp ( word [ 3 ] , " SEND " ) )
{
dcc = find_dcc ( word [ 4 ] , word [ 5 ] , TYPE_SEND ) ;
dcc_abort ( sess , dcc ) ;
goodtype = TRUE ;
}
if ( ! strcasecmp ( word [ 3 ] , " GET " ) )
{
dcc = find_dcc ( word [ 4 ] , word [ 5 ] , TYPE_RECV ) ;
dcc_abort ( sess , dcc ) ;
goodtype = TRUE ;
}
if ( ! strcasecmp ( word [ 3 ] , " CHAT " ) )
{
dcc = find_dcc ( word [ 4 ] , " " , TYPE_CHATRECV ) ;
if ( ! dcc )
dcc = find_dcc ( word [ 4 ] , " " , TYPE_CHATSEND ) ;
dcc_abort ( sess , dcc ) ;
goodtype = TRUE ;
}
if ( ! goodtype )
return FALSE ;
if ( ! dcc )
EMIT_SIGNAL ( XP_TE_NODCC , sess , NULL , NULL , NULL , NULL , 0 ) ;
return TRUE ;
}
return FALSE ;
}
if ( ( ! strcasecmp ( type , " CHAT " ) ) | | ( ! strcasecmp ( type , " PCHAT " ) ) )
{
char * nick = word [ 3 ] ;
int passive = ( ! strcasecmp ( type , " PCHAT " ) ) ? 1 : 0 ;
if ( * nick )
dcc_chat ( sess , nick , passive ) ;
return TRUE ;
}
if ( ! strcasecmp ( type , " LIST " ) )
{
dcc_show_list ( sess ) ;
return TRUE ;
}
if ( ! strcasecmp ( type , " GET " ) )
{
char * nick = word [ 3 ] ;
char * file = word [ 4 ] ;
if ( ! * file )
{
if ( * nick )
dcc_get_nick ( sess , nick ) ;
} else
{
dcc = find_dcc ( nick , file , TYPE_RECV ) ;
if ( dcc )
dcc_get ( dcc ) ;
else
EMIT_SIGNAL ( XP_TE_NODCC , sess , NULL , NULL , NULL , NULL , 0 ) ;
}
return TRUE ;
}
if ( ( ! strcasecmp ( type , " SEND " ) ) | | ( ! strcasecmp ( type , " PSEND " ) ) )
{
int i = 3 , maxcps ;
char * nick , * file ;
int passive = ( ! strcasecmp ( type , " PSEND " ) ) ? 1 : 0 ;
nick = word [ i ] ;
if ( ! * nick )
return FALSE ;
maxcps = prefs . dcc_max_send_cps ;
if ( ! strncasecmp ( nick , " -maxcps= " , 8 ) )
{
maxcps = atoi ( nick + 8 ) ;
i + + ;
nick = word [ i ] ;
if ( ! * nick )
return FALSE ;
}
i + + ;
file = word [ i ] ;
if ( ! * file )
{
fe_dcc_send_filereq ( sess , nick , maxcps , passive ) ;
return TRUE ;
}
do
{
dcc_send ( sess , nick , file , maxcps , passive ) ;
i + + ;
file = word [ i ] ;
}
while ( * file ) ;
return TRUE ;
}
return FALSE ;
}
dcc_show_list ( sess ) ;
return TRUE ;
}
static int
cmd_debug ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
struct session * s ;
struct server * v ;
GSList * list = sess_list ;
PrintText ( sess , " Session T Channel WaitChan WillChan Server \n " ) ;
while ( list )
{
s = ( struct session * ) list - > data ;
sprintf ( tbuf , " %p %1x %-10.10s %-10.10s %-10.10s %p \n " ,
s , s - > type , s - > channel , s - > waitchannel ,
s - > willjoinchannel , s - > server ) ;
PrintText ( sess , tbuf ) ;
list = list - > next ;
}
list = serv_list ;
PrintText ( sess , " Server Sock Name \n " ) ;
while ( list )
{
v = ( struct server * ) list - > data ;
sprintf ( tbuf , " %p %-5d %s \n " ,
v , v - > sok , v - > servername ) ;
PrintText ( sess , tbuf ) ;
list = list - > next ;
}
sprintf ( tbuf ,
" \n front_session: %p \n "
" current_tab: %p \n \n " ,
sess - > server - > front_session , current_tab ) ;
PrintText ( sess , tbuf ) ;
# ifdef USE_DEBUG
sprintf ( tbuf , " current mem: %d \n \n " , current_mem_usage ) ;
PrintText ( sess , tbuf ) ;
# endif /* !MEMORY_DEBUG */
return TRUE ;
}
static int
cmd_delbutton ( struct session * sess , char * tbuf , char * word [ ] ,
char * word_eol [ ] )
{
if ( * word [ 2 ] )
{
if ( sess - > type = = SESS_DIALOG )
{
if ( list_delentry ( & dlgbutton_list , word [ 2 ] ) )
fe_dlgbuttons_update ( sess ) ;
} else
{
if ( list_delentry ( & button_list , word [ 2 ] ) )
fe_buttons_update ( sess ) ;
}
return TRUE ;
}
return FALSE ;
}
static int
cmd_dehop ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int i = 2 ;
while ( 1 )
{
if ( ! * word [ i ] )
{
if ( i = = 2 )
return FALSE ;
send_channel_modes ( sess , tbuf , word , 2 , i , ' - ' , ' h ' , 0 ) ;
return TRUE ;
}
i + + ;
}
}
static int
cmd_deop ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int i = 2 ;
while ( 1 )
{
if ( ! * word [ i ] )
{
if ( i = = 2 )
return FALSE ;
send_channel_modes ( sess , tbuf , word , 2 , i , ' - ' , ' o ' , 0 ) ;
return TRUE ;
}
i + + ;
}
}
typedef struct
{
char * * nicks ;
int i ;
session * sess ;
char * reason ;
char * tbuf ;
} multidata ;
static int
mdehop_cb ( struct User * user , multidata * data )
{
if ( user - > hop & & ! user - > me )
{
data - > nicks [ data - > i ] = user - > nick ;
data - > i + + ;
}
return TRUE ;
}
static int
cmd_mdehop ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * * nicks = malloc ( sizeof ( char * ) * sess - > hops ) ;
multidata data ;
data . nicks = nicks ;
data . i = 0 ;
tree_foreach ( sess - > usertree , ( tree_traverse_func * ) mdehop_cb , & data ) ;
send_channel_modes ( sess , tbuf , nicks , 0 , data . i , ' - ' , ' h ' , 0 ) ;
free ( nicks ) ;
return TRUE ;
}
static int
mdeop_cb ( struct User * user , multidata * data )
{
if ( user - > op & & ! user - > me )
{
data - > nicks [ data - > i ] = user - > nick ;
data - > i + + ;
}
return TRUE ;
}
static int
cmd_mdeop ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * * nicks = malloc ( sizeof ( char * ) * sess - > ops ) ;
multidata data ;
data . nicks = nicks ;
data . i = 0 ;
tree_foreach ( sess - > usertree , ( tree_traverse_func * ) mdeop_cb , & data ) ;
send_channel_modes ( sess , tbuf , nicks , 0 , data . i , ' - ' , ' o ' , 0 ) ;
free ( nicks ) ;
return TRUE ;
}
GSList * menu_list = NULL ;
static void
menu_free ( menu_entry * me )
{
free ( me - > path ) ;
if ( me - > label )
free ( me - > label ) ;
if ( me - > cmd )
free ( me - > cmd ) ;
if ( me - > ucmd )
free ( me - > ucmd ) ;
if ( me - > group )
free ( me - > group ) ;
if ( me - > icon )
free ( me - > icon ) ;
free ( me ) ;
}
/* strings equal? but ignore underscores */
int
menu_streq ( const char * s1 , const char * s2 , int def )
{
/* for separators */
if ( s1 = = NULL & & s2 = = NULL )
return 0 ;
if ( s1 = = NULL | | s2 = = NULL )
return 1 ;
while ( * s1 )
{
if ( * s1 = = ' _ ' )
s1 + + ;
if ( * s2 = = ' _ ' )
s2 + + ;
if ( * s1 ! = * s2 )
return 1 ;
s1 + + ;
s2 + + ;
}
if ( ! * s2 )
return 0 ;
return def ;
}
static menu_entry *
menu_entry_find ( char * path , char * label )
{
GSList * list ;
menu_entry * me ;
list = menu_list ;
while ( list )
{
me = list - > data ;
if ( ! strcmp ( path , me - > path ) )
{
if ( me - > label & & label & & ! strcmp ( label , me - > label ) )
return me ;
}
list = list - > next ;
}
return NULL ;
}
static void
menu_del_children ( char * path , char * label )
{
GSList * list , * next ;
menu_entry * me ;
char buf [ 512 ] ;
if ( ! label )
label = " " ;
if ( path [ 0 ] )
snprintf ( buf , sizeof ( buf ) , " %s/%s " , path , label ) ;
else
snprintf ( buf , sizeof ( buf ) , " %s " , label ) ;
list = menu_list ;
while ( list )
{
me = list - > data ;
next = list - > next ;
if ( ! menu_streq ( buf , me - > path , 0 ) )
{
menu_list = g_slist_remove ( menu_list , me ) ;
menu_free ( me ) ;
}
list = next ;
}
}
static int
menu_del ( char * path , char * label )
{
GSList * list ;
menu_entry * me ;
list = menu_list ;
while ( list )
{
me = list - > data ;
if ( ! menu_streq ( me - > label , label , 1 ) & & ! menu_streq ( me - > path , path , 1 ) )
{
menu_list = g_slist_remove ( menu_list , me ) ;
fe_menu_del ( me ) ;
menu_free ( me ) ;
/* delete this item's children, if any */
menu_del_children ( path , label ) ;
return 1 ;
}
list = list - > next ;
}
return 0 ;
}
static char
menu_is_mainmenu_root ( char * path , gint16 * offset )
{
static const char * menus [ ] = { " \ x4$TAB " , " \ x5$TRAY " , " \ x4$URL " , " \ x5$NICK " , " \ x5$CHAN " } ;
int i ;
for ( i = 0 ; i < 5 ; i + + )
{
if ( ! strncmp ( path , menus [ i ] + 1 , menus [ i ] [ 0 ] ) )
{
* offset = menus [ i ] [ 0 ] + 1 ; /* number of bytes to offset the root */
return 0 ; /* is not main menu */
}
}
* offset = 0 ;
return 1 ; /* is main menu */
}
static void
menu_add ( char * path , char * label , char * cmd , char * ucmd , int pos , int state , int markup , int enable , int mod , int key , char * group , char * icon )
{
menu_entry * me ;
/* already exists? */
me = menu_entry_find ( path , label ) ;
if ( me )
{
/* update only */
me - > state = state ;
me - > enable = enable ;
fe_menu_update ( me ) ;
return ;
}
me = malloc ( sizeof ( menu_entry ) ) ;
me - > pos = pos ;
me - > modifier = mod ;
me - > is_main = menu_is_mainmenu_root ( path , & me - > root_offset ) ;
me - > state = state ;
me - > markup = markup ;
me - > enable = enable ;
me - > key = key ;
me - > path = strdup ( path ) ;
me - > label = NULL ;
me - > cmd = NULL ;
me - > ucmd = NULL ;
me - > group = NULL ;
me - > icon = NULL ;
if ( label )
me - > label = strdup ( label ) ;
if ( cmd )
me - > cmd = strdup ( cmd ) ;
if ( ucmd )
me - > ucmd = strdup ( ucmd ) ;
if ( group )
me - > group = strdup ( group ) ;
if ( icon )
me - > icon = strdup ( icon ) ;
menu_list = g_slist_append ( menu_list , me ) ;
label = fe_menu_add ( me ) ;
if ( label )
{
/* FE has given us a stripped label */
free ( me - > label ) ;
me - > label = strdup ( label ) ;
g_free ( label ) ; /* this is from pango */
}
}
static int
cmd_menu ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int idx = 2 ;
int len ;
int pos = 0xffff ;
int state ;
int toggle = FALSE ;
int enable = TRUE ;
int markup = FALSE ;
int key = 0 ;
int mod = 0 ;
char * label ;
char * group = NULL ;
char * icon = NULL ;
if ( ! word [ 2 ] [ 0 ] | | ! word [ 3 ] [ 0 ] )
return FALSE ;
/* -eX enabled or not? */
if ( word [ idx ] [ 0 ] = = ' - ' & & word [ idx ] [ 1 ] = = ' e ' )
{
enable = atoi ( word [ idx ] + 2 ) ;
idx + + ;
}
/* -i<ICONFILE> */
if ( word [ idx ] [ 0 ] = = ' - ' & & word [ idx ] [ 1 ] = = ' i ' )
{
icon = word [ idx ] + 2 ;
idx + + ;
}
/* -k<mod>,<key> key binding */
if ( word [ idx ] [ 0 ] = = ' - ' & & word [ idx ] [ 1 ] = = ' k ' )
{
char * comma = strchr ( word [ idx ] , ' , ' ) ;
if ( ! comma )
return FALSE ;
mod = atoi ( word [ idx ] + 2 ) ;
key = atoi ( comma + 1 ) ;
idx + + ;
}
/* -m to specify PangoMarkup language */
if ( word [ idx ] [ 0 ] = = ' - ' & & word [ idx ] [ 1 ] = = ' m ' )
{
markup = TRUE ;
idx + + ;
}
/* -pX to specify menu position */
if ( word [ idx ] [ 0 ] = = ' - ' & & word [ idx ] [ 1 ] = = ' p ' )
{
pos = atoi ( word [ idx ] + 2 ) ;
idx + + ;
}
/* -rSTATE,GROUP to specify a radio item */
if ( word [ idx ] [ 0 ] = = ' - ' & & word [ idx ] [ 1 ] = = ' r ' )
{
state = atoi ( word [ idx ] + 2 ) ;
group = word [ idx ] + 4 ;
idx + + ;
}
/* -tX to specify toggle item with default state */
if ( word [ idx ] [ 0 ] = = ' - ' & & word [ idx ] [ 1 ] = = ' t ' )
{
state = atoi ( word [ idx ] + 2 ) ;
idx + + ;
toggle = TRUE ;
}
if ( word [ idx + 1 ] [ 0 ] = = 0 )
return FALSE ;
/* the path */
path_part ( word [ idx + 1 ] , tbuf , 512 ) ;
len = strlen ( tbuf ) ;
if ( len )
tbuf [ len - 1 ] = 0 ;
/* the name of the item */
label = file_part ( word [ idx + 1 ] ) ;
if ( label [ 0 ] = = ' - ' & & label [ 1 ] = = 0 )
label = NULL ; /* separator */
if ( markup )
{
char * p ; /* to force pango closing tags through */
for ( p = label ; * p ; p + + )
if ( * p = = 3 )
* p = ' / ' ;
}
if ( ! strcasecmp ( word [ idx ] , " ADD " ) )
{
if ( toggle )
{
menu_add ( tbuf , label , word [ idx + 2 ] , word [ idx + 3 ] , pos , state , markup , enable , mod , key , NULL , NULL ) ;
} else
{
if ( word [ idx + 2 ] [ 0 ] )
menu_add ( tbuf , label , word [ idx + 2 ] , NULL , pos , state , markup , enable , mod , key , group , icon ) ;
else
menu_add ( tbuf , label , NULL , NULL , pos , state , markup , enable , mod , key , group , icon ) ;
}
return TRUE ;
}
if ( ! strcasecmp ( word [ idx ] , " DEL " ) )
{
menu_del ( tbuf , label ) ;
return TRUE ;
}
return FALSE ;
}
static int
mkick_cb ( struct User * user , multidata * data )
{
if ( ! user - > op & & ! user - > me )
data - > sess - > server - > p_kick ( data - > sess - > server , data - > sess - > channel , user - > nick , data - > reason ) ;
return TRUE ;
}
static int
mkickops_cb ( struct User * user , multidata * data )
{
if ( user - > op & & ! user - > me )
data - > sess - > server - > p_kick ( data - > sess - > server , data - > sess - > channel , user - > nick , data - > reason ) ;
return TRUE ;
}
static int
cmd_mkick ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
multidata data ;
data . sess = sess ;
data . reason = word_eol [ 2 ] ;
tree_foreach ( sess - > usertree , ( tree_traverse_func * ) mkickops_cb , & data ) ;
tree_foreach ( sess - > usertree , ( tree_traverse_func * ) mkick_cb , & data ) ;
return TRUE ;
}
static int
cmd_devoice ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int i = 2 ;
while ( 1 )
{
if ( ! * word [ i ] )
{
if ( i = = 2 )
return FALSE ;
send_channel_modes ( sess , tbuf , word , 2 , i , ' - ' , ' v ' , 0 ) ;
return TRUE ;
}
i + + ;
}
}
static int
cmd_discon ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
sess - > server - > disconnect ( sess , TRUE , - 1 ) ;
return TRUE ;
}
static int
cmd_dns ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
# ifdef WIN32
PrintText ( sess , " DNS is not implemented in Windows. \n " ) ;
return TRUE ;
# else
char * nick = word [ 2 ] ;
struct User * user ;
if ( * nick )
{
if ( strchr ( nick , ' . ' ) = = NULL )
{
user = userlist_find ( sess , nick ) ;
if ( user & & user - > hostname )
{
do_dns ( sess , user - > nick , user - > hostname ) ;
} else
{
sess - > server - > p_get_ip ( sess - > server , nick ) ;
sess - > server - > doing_dns = TRUE ;
}
} else
{
snprintf ( tbuf , TBUFSIZE , " exec -d %s %s " , prefs . dnsprogram , nick ) ;
handle_command ( sess , tbuf , FALSE ) ;
}
return TRUE ;
}
return FALSE ;
# endif
}
static int
cmd_echo ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
PrintText ( sess , word_eol [ 2 ] ) ;
return TRUE ;
}
# ifndef WIN32
static void
exec_check_process ( struct session * sess )
{
int val ;
if ( sess - > running_exec = = NULL )
return ;
val = waitpid ( sess - > running_exec - > childpid , NULL , WNOHANG ) ;
if ( val = = - 1 | | val > 0 )
{
close ( sess - > running_exec - > myfd ) ;
fe_input_remove ( sess - > running_exec - > iotag ) ;
free ( sess - > running_exec ) ;
sess - > running_exec = NULL ;
}
}
# ifndef __EMX__
static int
cmd_execs ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int r ;
exec_check_process ( sess ) ;
if ( sess - > running_exec = = NULL )
{
EMIT_SIGNAL ( XP_TE_NOCHILD , sess , NULL , NULL , NULL , NULL , 0 ) ;
return FALSE ;
}
r = kill ( sess - > running_exec - > childpid , SIGSTOP ) ;
if ( r = = - 1 )
PrintText ( sess , " Error in kill(2) \n " ) ;
return TRUE ;
}
static int
cmd_execc ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int r ;
exec_check_process ( sess ) ;
if ( sess - > running_exec = = NULL )
{
EMIT_SIGNAL ( XP_TE_NOCHILD , sess , NULL , NULL , NULL , NULL , 0 ) ;
return FALSE ;
}
r = kill ( sess - > running_exec - > childpid , SIGCONT ) ;
if ( r = = - 1 )
PrintText ( sess , " Error in kill(2) \n " ) ;
return TRUE ;
}
static int
cmd_execk ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int r ;
exec_check_process ( sess ) ;
if ( sess - > running_exec = = NULL )
{
EMIT_SIGNAL ( XP_TE_NOCHILD , sess , NULL , NULL , NULL , NULL , 0 ) ;
return FALSE ;
}
if ( strcmp ( word [ 2 ] , " -9 " ) = = 0 )
r = kill ( sess - > running_exec - > childpid , SIGKILL ) ;
else
r = kill ( sess - > running_exec - > childpid , SIGTERM ) ;
if ( r = = - 1 )
PrintText ( sess , " Error in kill(2) \n " ) ;
return TRUE ;
}
/* OS/2 Can't have the /EXECW command because it uses pipe(2) not socketpair
and thus it is simplex - - AGL */
static int
cmd_execw ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int len ;
char * temp ;
exec_check_process ( sess ) ;
if ( sess - > running_exec = = NULL )
{
EMIT_SIGNAL ( XP_TE_NOCHILD , sess , NULL , NULL , NULL , NULL , 0 ) ;
return FALSE ;
}
len = strlen ( word_eol [ 2 ] ) ;
temp = malloc ( len + 2 ) ;
sprintf ( temp , " %s \n " , word_eol [ 2 ] ) ;
PrintText ( sess , temp ) ;
write ( sess - > running_exec - > myfd , temp , len + 1 ) ;
free ( temp ) ;
return TRUE ;
}
# endif /* !__EMX__ */
/* convert ANSI escape color codes to mIRC codes */
static short escconv [ ] =
/* 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 */
{ 1 , 4 , 3 , 5 , 2 , 10 , 6 , 1 , 1 , 7 , 9 , 8 , 12 , 11 , 13 , 1 } ;
static void
exec_handle_colors ( char * buf , int len )
{
char numb [ 16 ] ;
char * nbuf ;
int i = 0 , j = 0 , k = 0 , firstn = 0 , col , colf = 0 , colb = 0 ;
int esc = FALSE , backc = FALSE , bold = FALSE ;
/* any escape codes in this text? */
if ( strchr ( buf , 27 ) = = 0 )
return ;
nbuf = malloc ( len + 1 ) ;
while ( i < len )
{
switch ( buf [ i ] )
{
case ' \r ' :
break ;
case 27 :
esc = TRUE ;
break ;
case ' ; ' :
if ( ! esc )
goto norm ;
backc = TRUE ;
numb [ k ] = 0 ;
firstn = atoi ( numb ) ;
k = 0 ;
break ;
case ' [ ' :
if ( ! esc )
goto norm ;
break ;
default :
if ( esc )
{
if ( buf [ i ] > = ' A ' & & buf [ i ] < = ' z ' )
{
if ( buf [ i ] = = ' m ' )
{
/* ^[[0m */
if ( k = = 0 | | ( numb [ 0 ] = = ' 0 ' & & k = = 1 ) )
{
nbuf [ j ] = ' \017 ' ;
j + + ;
bold = FALSE ;
goto cont ;
}
numb [ k ] = 0 ;
col = atoi ( numb ) ;
backc = FALSE ;
if ( firstn = = 1 )
bold = TRUE ;
if ( firstn > = 30 & & firstn < = 37 )
colf = firstn - 30 ;
if ( col > = 40 )
{
colb = col - 40 ;
backc = TRUE ;
}
if ( col > = 30 & & col < = 37 )
colf = col - 30 ;
if ( bold )
colf + = 8 ;
if ( backc )
{
colb = escconv [ colb % 14 ] ;
colf = escconv [ colf % 14 ] ;
j + = sprintf ( & nbuf [ j ] , " \003 %d,%02d " , colf , colb ) ;
} else
{
colf = escconv [ colf % 14 ] ;
j + = sprintf ( & nbuf [ j ] , " \003 %02d " , colf ) ;
}
}
cont : esc = FALSE ;
backc = FALSE ;
k = 0 ;
} else
{
if ( isdigit ( ( unsigned char ) buf [ i ] ) & & k < ( sizeof ( numb ) - 1 ) )
{
numb [ k ] = buf [ i ] ;
k + + ;
}
}
} else
{
norm : nbuf [ j ] = buf [ i ] ;
j + + ;
}
}
i + + ;
}
nbuf [ j ] = 0 ;
memcpy ( buf , nbuf , j + 1 ) ;
free ( nbuf ) ;
}
# ifndef HAVE_MEMRCHR
static void *
memrchr ( const void * block , int c , size_t size )
{
unsigned char * p ;
for ( p = ( unsigned char * ) block + size ; p ! = block ; p - - )
if ( * p = = c )
return p ;
return 0 ;
}
# endif
static gboolean
exec_data ( GIOChannel * source , GIOCondition condition , struct nbexec * s )
{
char * buf , * readpos , * rest ;
int rd , len ;
int sok = s - > myfd ;
len = s - > buffill ;
if ( len ) {
/* append new data to buffered incomplete line */
buf = malloc ( len + 2050 ) ;
memcpy ( buf , s - > linebuf , len ) ;
readpos = buf + len ;
free ( s - > linebuf ) ;
s - > linebuf = NULL ;
}
else
readpos = buf = malloc ( 2050 ) ;
rd = read ( sok , readpos , 2048 ) ;
if ( rd < 1 )
{
/* The process has died */
kill ( s - > childpid , SIGKILL ) ;
if ( len ) {
buf [ len ] = ' \0 ' ;
exec_handle_colors ( buf , len ) ;
if ( s - > tochannel )
{
/* must turn off auto-completion temporarily */
unsigned int old = prefs . nickcompletion ;
prefs . nickcompletion = 0 ;
handle_multiline ( s - > sess , buf , FALSE , TRUE ) ;
prefs . nickcompletion = old ;
}
else
PrintText ( s - > sess , buf ) ;
}
free ( buf ) ;
waitpid ( s - > childpid , NULL , 0 ) ;
s - > sess - > running_exec = NULL ;
fe_input_remove ( s - > iotag ) ;
close ( sok ) ;
free ( s ) ;
return TRUE ;
}
len + = rd ;
buf [ len ] = ' \0 ' ;
rest = memrchr ( buf , ' \n ' , len ) ;
if ( rest )
rest + + ;
else
rest = buf ;
if ( * rest ) {
s - > buffill = len - ( rest - buf ) ; /* = strlen(rest) */
s - > linebuf = malloc ( s - > buffill ) ;
memcpy ( s - > linebuf , rest , s - > buffill ) ;
* rest = ' \0 ' ;
len - = s - > buffill ; /* possibly 0 */
}
else
s - > buffill = 0 ;
if ( len ) {
exec_handle_colors ( buf , len ) ;
if ( s - > tochannel )
handle_multiline ( s - > sess , buf , FALSE , TRUE ) ;
else
PrintText ( s - > sess , buf ) ;
}
free ( buf ) ;
return TRUE ;
}
static int
cmd_exec ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int tochannel = FALSE ;
char * cmd = word_eol [ 2 ] ;
int fds [ 2 ] , pid = 0 ;
struct nbexec * s ;
int shell = TRUE ;
int fd ;
if ( * cmd )
{
exec_check_process ( sess ) ;
if ( sess - > running_exec ! = NULL )
{
EMIT_SIGNAL ( XP_TE_ALREADYPROCESS , sess , NULL , NULL , NULL , NULL , 0 ) ;
return TRUE ;
}
if ( ! strcmp ( word [ 2 ] , " -d " ) )
{
if ( ! * word [ 3 ] )
return FALSE ;
cmd = word_eol [ 3 ] ;
shell = FALSE ;
}
else if ( ! strcmp ( word [ 2 ] , " -o " ) )
{
if ( ! * word [ 3 ] )
return FALSE ;
cmd = word_eol [ 3 ] ;
tochannel = TRUE ;
}
if ( shell )
{
if ( access ( " /bin/sh " , X_OK ) ! = 0 )
{
fe_message ( _ ( " I need /bin/sh to run! \n " ) , FE_MSG_ERROR ) ;
return TRUE ;
}
}
# ifdef __EMX__ /* if os/2 */
if ( pipe ( fds ) < 0 )
{
PrintText ( sess , " Pipe create error \n " ) ;
return FALSE ;
}
setmode ( fds [ 0 ] , O_BINARY ) ;
setmode ( fds [ 1 ] , O_BINARY ) ;
# else
if ( socketpair ( PF_UNIX , SOCK_STREAM , 0 , fds ) = = - 1 )
{
PrintText ( sess , " socketpair(2) failed \n " ) ;
return FALSE ;
}
# endif
s = ( struct nbexec * ) malloc ( sizeof ( struct nbexec ) ) ;
memset ( s , 0 , sizeof ( * s ) ) ;
s - > myfd = fds [ 0 ] ;
s - > tochannel = tochannel ;
s - > sess = sess ;
pid = fork ( ) ;
if ( pid = = 0 )
{
/* This is the child's context */
close ( 0 ) ;
close ( 1 ) ;
close ( 2 ) ;
/* Close parent's end of pipe */
close ( s - > myfd ) ;
/* Copy the child end of the pipe to stdout and stderr */
dup2 ( fds [ 1 ] , 1 ) ;
dup2 ( fds [ 1 ] , 2 ) ;
/* Also copy it to stdin so we can write to it */
dup2 ( fds [ 1 ] , 0 ) ;
/* Now close all open file descriptors except stdin, stdout and stderr */
for ( fd = 3 ; fd < 1024 ; fd + + ) close ( fd ) ;
/* Now we call /bin/sh to run our cmd ; made it more friendly -DC1 */
if ( shell )
{
execl ( " /bin/sh " , " sh " , " -c " , cmd , NULL ) ;
} else
{
char * * argv ;
int argc ;
my_poptParseArgvString ( cmd , & argc , & argv ) ;
execvp ( argv [ 0 ] , argv ) ;
}
/* not reached unless error */
/*printf("exec error\n");*/
fflush ( stdout ) ;
fflush ( stdin ) ;
_exit ( 0 ) ;
}
if ( pid = = - 1 )
{
/* Parent context, fork() failed */
PrintText ( sess , " Error in fork(2) \n " ) ;
close ( fds [ 0 ] ) ;
close ( fds [ 1 ] ) ;
} else
{
/* Parent path */
close ( fds [ 1 ] ) ;
s - > childpid = pid ;
s - > iotag = fe_input_add ( s - > myfd , FIA_READ | FIA_EX , exec_data , s ) ;
sess - > running_exec = s ;
return TRUE ;
}
}
return FALSE ;
}
# endif
static int
cmd_flushq ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
sprintf ( tbuf , " Flushing server send queue, %d bytes. \n " , sess - > server - > sendq_len ) ;
PrintText ( sess , tbuf ) ;
sess - > server - > flush_queue ( sess - > server ) ;
return TRUE ;
}
static int
cmd_quit ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( * word_eol [ 2 ] )
sess - > quitreason = word_eol [ 2 ] ;
sess - > server - > disconnect ( sess , TRUE , - 1 ) ;
sess - > quitreason = NULL ;
return 2 ;
}
static int
cmd_gate ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * server_name = word [ 2 ] ;
server * serv = sess - > server ;
if ( * server_name )
{
char * port = word [ 3 ] ;
# ifdef USE_OPENSSL
serv - > use_ssl = FALSE ;
# endif
server_fill_her_up ( serv ) ;
if ( * port )
serv - > connect ( serv , server_name , atoi ( port ) , TRUE ) ;
else
serv - > connect ( serv , server_name , 23 , TRUE ) ;
return TRUE ;
}
return FALSE ;
}
typedef struct
{
char * cmd ;
session * sess ;
} getvalinfo ;
static void
get_int_cb ( int cancel , int val , getvalinfo * info )
{
char buf [ 512 ] ;
if ( ! cancel )
{
snprintf ( buf , sizeof ( buf ) , " %s %d " , info - > cmd , val ) ;
if ( is_session ( info - > sess ) )
handle_command ( info - > sess , buf , FALSE ) ;
}
free ( info - > cmd ) ;
free ( info ) ;
}
static int
cmd_getint ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
getvalinfo * info ;
if ( ! word [ 4 ] [ 0 ] )
return FALSE ;
info = malloc ( sizeof ( * info ) ) ;
info - > cmd = strdup ( word [ 3 ] ) ;
info - > sess = sess ;
fe_get_int ( word [ 4 ] , atoi ( word [ 2 ] ) , get_int_cb , info ) ;
return TRUE ;
}
static void
get_file_cb ( char * cmd , char * file )
{
char buf [ 1024 + 128 ] ;
/* execute the command once per file, then once more with
no args */
if ( file )
{
snprintf ( buf , sizeof ( buf ) , " %s %s " , cmd , file ) ;
handle_command ( current_sess , buf , FALSE ) ;
}
else
{
handle_command ( current_sess , cmd , FALSE ) ;
free ( cmd ) ;
}
}
static int
cmd_getfile ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int idx = 2 ;
int flags = 0 ;
if ( ! word [ 3 ] [ 0 ] )
return FALSE ;
if ( ! strcmp ( word [ 2 ] , " -folder " ) )
{
flags | = FRF_CHOOSEFOLDER ;
idx + + ;
}
if ( ! strcmp ( word [ idx ] , " -multi " ) )
{
flags | = FRF_MULTIPLE ;
idx + + ;
}
if ( ! strcmp ( word [ idx ] , " -save " ) )
{
flags | = FRF_WRITE ;
idx + + ;
}
fe_get_file ( word [ idx + 1 ] , word [ idx + 2 ] , ( void * ) get_file_cb , strdup ( word [ idx ] ) , flags ) ;
return TRUE ;
}
static void
get_str_cb ( int cancel , char * val , getvalinfo * info )
{
char buf [ 512 ] ;
if ( ! cancel )
{
snprintf ( buf , sizeof ( buf ) , " %s %s " , info - > cmd , val ) ;
if ( is_session ( info - > sess ) )
handle_command ( info - > sess , buf , FALSE ) ;
}
free ( info - > cmd ) ;
free ( info ) ;
}
static int
cmd_getstr ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
getvalinfo * info ;
if ( ! word [ 4 ] [ 0 ] )
return FALSE ;
info = malloc ( sizeof ( * info ) ) ;
info - > cmd = strdup ( word [ 3 ] ) ;
info - > sess = sess ;
fe_get_str ( word [ 4 ] , word [ 2 ] , get_str_cb , info ) ;
return TRUE ;
}
static int
cmd_ghost ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( ! word [ 2 ] [ 0 ] )
return FALSE ;
sess - > server - > p_ns_ghost ( sess - > server , word [ 2 ] , word [ 3 ] ) ;
return TRUE ;
}
static int
cmd_gui ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
switch ( str_ihash ( word [ 2 ] ) )
{
case 0x058b836e : fe_ctrl_gui ( sess , 8 , 0 ) ; break ; /* APPLY */
case 0xac1eee45 : fe_ctrl_gui ( sess , 7 , 2 ) ; break ; /* ATTACH */
case 0x05a72f63 : fe_ctrl_gui ( sess , 4 , atoi ( word [ 3 ] ) ) ; break ; /* COLOR */
case 0xb06a1793 : fe_ctrl_gui ( sess , 7 , 1 ) ; break ; /* DETACH */
case 0x05cfeff0 : fe_ctrl_gui ( sess , 3 , 0 ) ; break ; /* FLASH */
case 0x05d154d8 : fe_ctrl_gui ( sess , 2 , 0 ) ; break ; /* FOCUS */
case 0x0030dd42 : fe_ctrl_gui ( sess , 0 , 0 ) ; break ; /* HIDE */
case 0x61addbe3 : fe_ctrl_gui ( sess , 5 , 0 ) ; break ; /* ICONIFY */
case 0xc0851aaa : fe_message ( word [ 3 ] , FE_MSG_INFO | FE_MSG_MARKUP ) ; break ; /* MSGBOX */
case 0x0035dafd : fe_ctrl_gui ( sess , 1 , 0 ) ; break ; /* SHOW */
case 0x0033155f : /* MENU */
if ( ! strcasecmp ( word [ 3 ] , " TOGGLE " ) )
fe_ctrl_gui ( sess , 6 , 0 ) ;
else
return FALSE ;
break ;
default :
return FALSE ;
}
return TRUE ;
}
typedef struct
{
int longfmt ;
int i , t ;
char * buf ;
} help_list ;
static void
show_help_line ( session * sess , help_list * hl , char * name , char * usage )
{
int j , len , max ;
char * p ;
if ( name [ 0 ] = = ' . ' ) /* hidden command? */
return ;
if ( hl - > longfmt ) /* long format for /HELP -l */
{
if ( ! usage | | usage [ 0 ] = = 0 )
PrintTextf ( sess , " \003 4%s \003 : \n " , name ) ;
else
PrintTextf ( sess , " \003 4%s \003 : %s \n " , name , _ ( usage ) ) ;
return ;
}
/* append the name into buffer, but convert to uppercase */
len = strlen ( hl - > buf ) ;
p = name ;
while ( * p )
{
hl - > buf [ len ] = toupper ( ( unsigned char ) * p ) ;
len + + ;
p + + ;
}
hl - > buf [ len ] = 0 ;
hl - > t + + ;
if ( hl - > t = = 5 )
{
hl - > t = 0 ;
strcat ( hl - > buf , " \n " ) ;
PrintText ( sess , hl - > buf ) ;
hl - > buf [ 0 ] = ' ' ;
hl - > buf [ 1 ] = ' ' ;
hl - > buf [ 2 ] = 0 ;
} else
{
/* append some spaces after the command name */
max = strlen ( name ) ;
if ( max < 10 )
{
max = 10 - max ;
for ( j = 0 ; j < max ; j + + )
{
hl - > buf [ len ] = ' ' ;
len + + ;
hl - > buf [ len ] = 0 ;
}
}
}
}
static int
cmd_help ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int i = 0 , longfmt = 0 ;
char * helpcmd = " " ;
GSList * list ;
if ( tbuf )
helpcmd = word [ 2 ] ;
if ( * helpcmd & & strcmp ( helpcmd , " -l " ) = = 0 )
longfmt = 1 ;
if ( * helpcmd & & ! longfmt )
{
help ( sess , tbuf , helpcmd , FALSE ) ;
} else
{
struct popup * pop ;
char * buf = malloc ( 4096 ) ;
help_list hl ;
hl . longfmt = longfmt ;
hl . buf = buf ;
PrintTextf ( sess , " \n %s \n \n " , _ ( " Commands Available: " ) ) ;
buf [ 0 ] = ' ' ;
buf [ 1 ] = ' ' ;
buf [ 2 ] = 0 ;
hl . t = 0 ;
hl . i = 0 ;
while ( xc_cmds [ i ] . name )
{
show_help_line ( sess , & hl , xc_cmds [ i ] . name , xc_cmds [ i ] . help ) ;
i + + ;
}
strcat ( buf , " \n " ) ;
PrintText ( sess , buf ) ;
PrintTextf ( sess , " \n %s \n \n " , _ ( " User defined commands: " ) ) ;
buf [ 0 ] = ' ' ;
buf [ 1 ] = ' ' ;
buf [ 2 ] = 0 ;
hl . t = 0 ;
hl . i = 0 ;
list = command_list ;
while ( list )
{
pop = list - > data ;
show_help_line ( sess , & hl , pop - > name , pop - > cmd ) ;
list = list - > next ;
}
strcat ( buf , " \n " ) ;
PrintText ( sess , buf ) ;
PrintTextf ( sess , " \n %s \n \n " , _ ( " Plugin defined commands: " ) ) ;
buf [ 0 ] = ' ' ;
buf [ 1 ] = ' ' ;
buf [ 2 ] = 0 ;
hl . t = 0 ;
hl . i = 0 ;
plugin_command_foreach ( sess , & hl , ( void * ) show_help_line ) ;
strcat ( buf , " \n " ) ;
PrintText ( sess , buf ) ;
free ( buf ) ;
PrintTextf ( sess , " \n %s \n \n " , _ ( " Type /HELP <command> for more information, or /HELP -l " ) ) ;
}
return TRUE ;
}
static int
cmd_id ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( word [ 2 ] [ 0 ] )
{
sess - > server - > p_ns_identify ( sess - > server , word [ 2 ] ) ;
return TRUE ;
}
return FALSE ;
}
static int
cmd_ignore ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int i ;
int type = 0 ;
int quiet = 0 ;
char * mask ;
if ( ! * word [ 2 ] )
{
ignore_showlist ( sess ) ;
return TRUE ;
}
if ( ! * word [ 3 ] )
return FALSE ;
i = 3 ;
while ( 1 )
{
if ( ! * word [ i ] )
{
if ( type = = 0 )
return FALSE ;
mask = word [ 2 ] ;
if ( strchr ( mask , ' ? ' ) = = NULL & &
strchr ( mask , ' * ' ) = = NULL & &
userlist_find ( sess , mask ) )
{
mask = tbuf ;
snprintf ( tbuf , TBUFSIZE , " %s!*@* " , word [ 2 ] ) ;
}
i = ignore_add ( mask , type ) ;
if ( quiet )
return TRUE ;
switch ( i )
{
case 1 :
EMIT_SIGNAL ( XP_TE_IGNOREADD , sess , mask , NULL , NULL , NULL , 0 ) ;
break ;
case 2 : /* old ignore changed */
EMIT_SIGNAL ( XP_TE_IGNORECHANGE , sess , mask , NULL , NULL , NULL , 0 ) ;
}
return TRUE ;
}
if ( ! strcasecmp ( word [ i ] , " UNIGNORE " ) )
type | = IG_UNIG ;
else if ( ! strcasecmp ( word [ i ] , " ALL " ) )
type | = IG_PRIV | IG_NOTI | IG_CHAN | IG_CTCP | IG_INVI | IG_DCC ;
else if ( ! strcasecmp ( word [ i ] , " PRIV " ) )
type | = IG_PRIV ;
else if ( ! strcasecmp ( word [ i ] , " NOTI " ) )
type | = IG_NOTI ;
else if ( ! strcasecmp ( word [ i ] , " CHAN " ) )
type | = IG_CHAN ;
else if ( ! strcasecmp ( word [ i ] , " CTCP " ) )
type | = IG_CTCP ;
else if ( ! strcasecmp ( word [ i ] , " INVI " ) )
type | = IG_INVI ;
else if ( ! strcasecmp ( word [ i ] , " QUIET " ) )
quiet = 1 ;
else if ( ! strcasecmp ( word [ i ] , " NOSAVE " ) )
type | = IG_NOSAVE ;
else if ( ! strcasecmp ( word [ i ] , " DCC " ) )
type | = IG_DCC ;
else
{
sprintf ( tbuf , _ ( " Unknown arg '%s' ignored. " ) , word [ i ] ) ;
PrintText ( sess , tbuf ) ;
}
i + + ;
}
}
static int
cmd_invite ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( ! * word [ 2 ] )
return FALSE ;
if ( * word [ 3 ] )
sess - > server - > p_invite ( sess - > server , word [ 3 ] , word [ 2 ] ) ;
else
sess - > server - > p_invite ( sess - > server , sess - > channel , word [ 2 ] ) ;
return TRUE ;
}
static int
cmd_join ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * chan = word [ 2 ] ;
if ( * chan )
{
char * po , * pass = word [ 3 ] ;
sess - > server - > p_join ( sess - > server , chan , pass ) ;
if ( sess - > channel [ 0 ] = = 0 & & sess - > waitchannel [ 0 ] )
{
po = strchr ( chan , ' , ' ) ;
if ( po )
* po = 0 ;
safe_strcpy ( sess - > waitchannel , chan , CHANLEN ) ;
}
return TRUE ;
}
return FALSE ;
}
static int
cmd_kick ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * nick = word [ 2 ] ;
char * reason = word_eol [ 3 ] ;
if ( * nick )
{
sess - > server - > p_kick ( sess - > server , sess - > channel , nick , reason ) ;
return TRUE ;
}
return FALSE ;
}
static int
cmd_kickban ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * nick = word [ 2 ] ;
char * reason = word_eol [ 3 ] ;
struct User * user ;
if ( * nick )
{
/* if the reason is a 1 digit number, treat it as a bantype */
user = userlist_find ( sess , nick ) ;
if ( isdigit ( ( unsigned char ) reason [ 0 ] ) & & reason [ 1 ] = = 0 )
{
ban ( sess , tbuf , nick , reason , ( user & & user - > op ) ) ;
reason [ 0 ] = 0 ;
} else
ban ( sess , tbuf , nick , " " , ( user & & user - > op ) ) ;
sess - > server - > p_kick ( sess - > server , sess - > channel , nick , reason ) ;
return TRUE ;
}
return FALSE ;
}
static int
cmd_killall ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
xchat_exit ( ) ;
return 2 ;
}
static int
cmd_lagcheck ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
lag_check ( ) ;
return TRUE ;
}
static void
lastlog ( session * sess , char * search , gboolean regexp )
{
session * lastlog_sess ;
if ( ! is_session ( sess ) )
return ;
lastlog_sess = find_dialog ( sess - > server , " (lastlog) " ) ;
if ( ! lastlog_sess )
lastlog_sess = new_ircwindow ( sess - > server , " (lastlog) " , SESS_DIALOG , 0 ) ;
lastlog_sess - > lastlog_sess = sess ;
lastlog_sess - > lastlog_regexp = regexp ; /* remember the search type */
fe_text_clear ( lastlog_sess , 0 ) ;
fe_lastlog ( sess , lastlog_sess , search , regexp ) ;
}
static int
cmd_lastlog ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( * word_eol [ 2 ] )
{
if ( ! strcmp ( word [ 2 ] , " -r " ) )
lastlog ( sess , word_eol [ 3 ] , TRUE ) ;
else
lastlog ( sess , word_eol [ 2 ] , FALSE ) ;
return TRUE ;
}
return FALSE ;
}
static int
cmd_list ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
sess - > server - > p_list_channels ( sess - > server , word_eol [ 2 ] , 1 ) ;
return TRUE ;
}
gboolean
load_perform_file ( session * sess , char * file )
{
char tbuf [ 1024 + 4 ] ;
char * nl ;
FILE * fp ;
fp = xchat_fopen_file ( file , " r " , XOF_FULLPATH ) ;
if ( ! fp )
return FALSE ;
tbuf [ 1024 ] = 0 ;
while ( fgets ( tbuf , 1024 , fp ) )
{
nl = strchr ( tbuf , ' \n ' ) ;
if ( nl = = tbuf ) /* skip empty commands */
continue ;
if ( nl )
* nl = 0 ;
if ( tbuf [ 0 ] = = prefs . cmdchar [ 0 ] )
handle_command ( sess , tbuf + 1 , TRUE ) ;
else
handle_command ( sess , tbuf , TRUE ) ;
}
fclose ( fp ) ;
return TRUE ;
}
static int
cmd_load ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * error , * arg , * file ;
int len ;
if ( ! word [ 2 ] [ 0 ] )
return FALSE ;
if ( strcmp ( word [ 2 ] , " -e " ) = = 0 )
{
file = expand_homedir ( word [ 3 ] ) ;
if ( ! load_perform_file ( sess , file ) )
{
PrintTextf ( sess , _ ( " Cannot access %s \n " ) , file ) ;
PrintText ( sess , errorstring ( errno ) ) ;
}
free ( file ) ;
return TRUE ;
}
# ifdef USE_PLUGIN
len = strlen ( word [ 2 ] ) ;
# ifdef WIN32
if ( len > 4 & & strcasecmp ( " .dll " , word [ 2 ] + len - 4 ) = = 0 )
# else
# if defined(__hpux)
if ( len > 3 & & strcasecmp ( " .sl " , word [ 2 ] + len - 3 ) = = 0 )
# else
if ( len > 3 & & strcasecmp ( " .so " , word [ 2 ] + len - 3 ) = = 0 )
# endif
# endif
{
arg = NULL ;
if ( word_eol [ 3 ] [ 0 ] )
arg = word_eol [ 3 ] ;
file = expand_homedir ( word [ 2 ] ) ;
error = plugin_load ( sess , file , arg ) ;
free ( file ) ;
if ( error )
PrintText ( sess , error ) ;
return TRUE ;
}
# endif
sprintf ( tbuf , " Unknown file type %s. Maybe you need to install the Perl or Python plugin? \n " , word [ 2 ] ) ;
PrintText ( sess , tbuf ) ;
return FALSE ;
}
static int
cmd_me ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * act = word_eol [ 2 ] ;
if ( ! ( * act ) )
return FALSE ;
if ( sess - > type = = SESS_SERVER )
{
notj_msg ( sess ) ;
return TRUE ;
}
snprintf ( tbuf , TBUFSIZE , " \001 ACTION %s \001 \r " , act ) ;
/* first try through DCC CHAT */
if ( dcc_write_chat ( sess - > channel , tbuf ) )
{
/* print it to screen */
inbound_action ( sess , sess - > channel , sess - > server - > nick , " " , act , TRUE , FALSE ) ;
} else
{
/* DCC CHAT failed, try through server */
if ( sess - > server - > connected )
{
sess - > server - > p_action ( sess - > server , sess - > channel , act ) ;
/* print it to screen */
inbound_action ( sess , sess - > channel , sess - > server - > nick , " " , act , TRUE , FALSE ) ;
} else
{
notc_msg ( sess ) ;
}
}
return TRUE ;
}
static int
cmd_mode ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
/* +channel channels are dying, let those servers whine about modes.
* return info about current channel if available and no info is given */
if ( ( * word [ 2 ] = = ' + ' ) | | ( * word [ 2 ] = = 0 ) | | ( ! is_channel ( sess - > server , word [ 2 ] ) & &
! ( rfc_casecmp ( sess - > server - > nick , word [ 2 ] ) = = 0 ) ) )
{
if ( sess - > channel [ 0 ] = = 0 )
return FALSE ;
sess - > server - > p_mode ( sess - > server , sess - > channel , word_eol [ 2 ] ) ;
}
else
sess - > server - > p_mode ( sess - > server , word [ 2 ] , word_eol [ 3 ] ) ;
return TRUE ;
}
static int
mop_cb ( struct User * user , multidata * data )
{
if ( ! user - > op )
{
data - > nicks [ data - > i ] = user - > nick ;
data - > i + + ;
}
return TRUE ;
}
static int
cmd_mop ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * * nicks = malloc ( sizeof ( char * ) * ( sess - > total - sess - > ops ) ) ;
multidata data ;
data . nicks = nicks ;
data . i = 0 ;
tree_foreach ( sess - > usertree , ( tree_traverse_func * ) mop_cb , & data ) ;
send_channel_modes ( sess , tbuf , nicks , 0 , data . i , ' + ' , ' o ' , 0 ) ;
free ( nicks ) ;
return TRUE ;
}
static int
cmd_msg ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * nick = word [ 2 ] ;
char * msg = word_eol [ 3 ] ;
struct session * newsess ;
if ( * nick )
{
if ( * msg )
{
if ( strcmp ( nick , " . " ) = = 0 )
{ /* /msg the last nick /msg'ed */
if ( sess - > lastnick [ 0 ] )
nick = sess - > lastnick ;
} else
{
safe_strcpy ( sess - > lastnick , nick , NICKLEN ) ; /* prime the last nick memory */
}
if ( * nick = = ' = ' )
{
nick + + ;
if ( ! dcc_write_chat ( nick , msg ) )
{
EMIT_SIGNAL ( XP_TE_NODCC , sess , NULL , NULL , NULL , NULL , 0 ) ;
return TRUE ;
}
} else
{
if ( ! sess - > server - > connected )
{
notc_msg ( sess ) ;
return TRUE ;
}
sess - > server - > p_message ( sess - > server , nick , msg ) ;
}
newsess = find_dialog ( sess - > server , nick ) ;
if ( ! newsess )
2011-08-08 19:57:42 -04:00
{
2011-02-23 22:14:30 -05:00
newsess = find_channel ( sess - > server , nick ) ;
2011-08-08 19:57:42 -04:00
if ( ! newsess & & prefs . gui_auto_open_msg )
{
newsess = new_ircwindow ( sess - > server , nick , SESS_DIALOG , 0 ) ;
}
}
2011-02-23 22:14:30 -05:00
if ( newsess )
inbound_chanmsg ( newsess - > server , NULL , newsess - > channel ,
newsess - > server - > nick , msg , TRUE , FALSE ) ;
else
{
/* mask out passwords */
if ( strcasecmp ( nick , " nickserv " ) = = 0 & &
strncasecmp ( msg , " identify " , 9 ) = = 0 )
msg = " identify **** " ;
EMIT_SIGNAL ( XP_TE_MSGSEND , sess , nick , msg , NULL , NULL , 0 ) ;
}
return TRUE ;
}
}
return FALSE ;
}
static int
cmd_names ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( * word [ 2 ] )
sess - > server - > p_names ( sess - > server , word [ 2 ] ) ;
else
sess - > server - > p_names ( sess - > server , sess - > channel ) ;
return TRUE ;
}
static int
cmd_nctcp ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( * word_eol [ 3 ] )
{
sess - > server - > p_nctcp ( sess - > server , word [ 2 ] , word_eol [ 3 ] ) ;
return TRUE ;
}
return FALSE ;
}
static int
cmd_newserver ( struct session * sess , char * tbuf , char * word [ ] ,
char * word_eol [ ] )
{
if ( strcmp ( word [ 2 ] , " -noconnect " ) = = 0 )
{
new_ircwindow ( NULL , word [ 3 ] , SESS_SERVER , 0 ) ;
return TRUE ;
}
sess = new_ircwindow ( NULL , NULL , SESS_SERVER , 0 ) ;
cmd_server ( sess , tbuf , word , word_eol ) ;
return TRUE ;
}
static int
cmd_nick ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * nick = word [ 2 ] ;
if ( * nick )
{
if ( sess - > server - > connected )
sess - > server - > p_change_nick ( sess - > server , nick ) ;
else
inbound_newnick ( sess - > server , sess - > server - > nick , nick , TRUE ) ;
return TRUE ;
}
return FALSE ;
}
static int
cmd_notice ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( * word [ 2 ] & & * word_eol [ 3 ] )
{
sess - > server - > p_notice ( sess - > server , word [ 2 ] , word_eol [ 3 ] ) ;
EMIT_SIGNAL ( XP_TE_NOTICESEND , sess , word [ 2 ] , word_eol [ 3 ] , NULL , NULL , 0 ) ;
return TRUE ;
}
return FALSE ;
}
static int
cmd_notify ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int i = 1 ;
char * net = NULL ;
if ( * word [ 2 ] )
{
if ( strcmp ( word [ 2 ] , " -n " ) = = 0 ) /* comma sep network list */
{
net = word [ 3 ] ;
i + = 2 ;
}
while ( 1 )
{
i + + ;
if ( ! * word [ i ] )
break ;
if ( notify_deluser ( word [ i ] ) )
{
EMIT_SIGNAL ( XP_TE_DELNOTIFY , sess , word [ i ] , NULL , NULL , NULL , 0 ) ;
return TRUE ;
}
if ( net & & strcmp ( net , " ASK " ) = = 0 )
fe_notify_ask ( word [ i ] , NULL ) ;
else
{
notify_adduser ( word [ i ] , net ) ;
EMIT_SIGNAL ( XP_TE_ADDNOTIFY , sess , word [ i ] , NULL , NULL , NULL , 0 ) ;
}
}
} else
notify_showlist ( sess ) ;
return TRUE ;
}
static int
cmd_op ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int i = 2 ;
while ( 1 )
{
if ( ! * word [ i ] )
{
if ( i = = 2 )
return FALSE ;
send_channel_modes ( sess , tbuf , word , 2 , i , ' + ' , ' o ' , 0 ) ;
return TRUE ;
}
i + + ;
}
}
static int
cmd_part ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * chan = word [ 2 ] ;
char * reason = word_eol [ 3 ] ;
if ( ! * chan )
chan = sess - > channel ;
if ( ( * chan ) & & is_channel ( sess - > server , chan ) )
{
if ( reason [ 0 ] = = 0 )
reason = NULL ;
server_sendpart ( sess - > server , chan , reason ) ;
return TRUE ;
}
return FALSE ;
}
static int
cmd_ping ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char timestring [ 64 ] ;
unsigned long tim ;
char * to = word [ 2 ] ;
tim = make_ping_time ( ) ;
snprintf ( timestring , sizeof ( timestring ) , " %lu " , tim ) ;
sess - > server - > p_ping ( sess - > server , to , timestring ) ;
return TRUE ;
}
void
open_query ( server * serv , char * nick , gboolean focus_existing )
{
session * sess ;
sess = find_dialog ( serv , nick ) ;
if ( ! sess )
new_ircwindow ( serv , nick , SESS_DIALOG , 1 ) ;
else if ( focus_existing )
fe_ctrl_gui ( sess , 2 , 0 ) ; /* bring-to-front */
}
static int
cmd_query ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * nick = word [ 2 ] ;
gboolean focus = TRUE ;
if ( strcmp ( word [ 2 ] , " -nofocus " ) = = 0 )
{
nick = word [ 3 ] ;
focus = FALSE ;
}
if ( * nick & & ! is_channel ( sess - > server , nick ) )
{
open_query ( sess - > server , nick , focus ) ;
return TRUE ;
}
return FALSE ;
}
static int
cmd_quote ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * raw = word_eol [ 2 ] ;
return sess - > server - > p_raw ( sess - > server , raw ) ;
}
static int
cmd_reconnect ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int tmp = prefs . recon_delay ;
GSList * list ;
server * serv = sess - > server ;
prefs . recon_delay = 0 ;
if ( ! strcasecmp ( word [ 2 ] , " ALL " ) )
{
list = serv_list ;
while ( list )
{
serv = list - > data ;
if ( serv - > connected )
serv - > auto_reconnect ( serv , TRUE , - 1 ) ;
list = list - > next ;
}
}
/* If it isn't "ALL" and there is something
there it * should * be a server they are trying to connect to */
else if ( * word [ 2 ] )
{
int offset = 0 ;
# ifdef USE_OPENSSL
int use_ssl = FALSE ;
if ( strcmp ( word [ 2 ] , " -ssl " ) = = 0 )
{
use_ssl = TRUE ;
offset + + ; /* args move up by 1 word */
}
serv - > use_ssl = use_ssl ;
serv - > accept_invalid_cert = TRUE ;
# endif
if ( * word [ 4 + offset ] )
safe_strcpy ( serv - > password , word [ 4 + offset ] , sizeof ( serv - > password ) ) ;
if ( * word [ 3 + offset ] )
serv - > port = atoi ( word [ 3 + offset ] ) ;
safe_strcpy ( serv - > hostname , word [ 2 + offset ] , sizeof ( serv - > hostname ) ) ;
serv - > auto_reconnect ( serv , TRUE , - 1 ) ;
}
else
{
serv - > auto_reconnect ( serv , TRUE , - 1 ) ;
}
prefs . recon_delay = tmp ;
return TRUE ;
}
static int
cmd_recv ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( * word_eol [ 2 ] )
{
sess - > server - > p_inline ( sess - > server , word_eol [ 2 ] , strlen ( word_eol [ 2 ] ) ) ;
return TRUE ;
}
return FALSE ;
}
2011-09-07 16:08:24 -04:00
static int
cmd_saveconf ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
save_config ( ) ;
return TRUE ;
}
2011-02-23 22:14:30 -05:00
static int
cmd_say ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
char * speech = word_eol [ 2 ] ;
if ( * speech )
{
handle_say ( sess , speech , FALSE ) ;
return TRUE ;
}
return FALSE ;
}
static int
cmd_send ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
guint32 addr ;
socklen_t len ;
struct sockaddr_in SAddr ;
if ( ! word [ 2 ] [ 0 ] )
return FALSE ;
addr = dcc_get_my_address ( ) ;
if ( addr = = 0 )
{
/* use the one from our connected server socket */
memset ( & SAddr , 0 , sizeof ( struct sockaddr_in ) ) ;
len = sizeof ( SAddr ) ;
getsockname ( sess - > server - > sok , ( struct sockaddr * ) & SAddr , & len ) ;
addr = SAddr . sin_addr . s_addr ;
}
addr = ntohl ( addr ) ;
if ( ( addr & 0xffff0000 ) = = 0xc0a80000 | | /* 192.168.x.x */
( addr & 0xff000000 ) = = 0x0a000000 ) /* 10.x.x.x */
/* we got a private net address, let's PSEND or it'll fail */
snprintf ( tbuf , 512 , " DCC PSEND %s " , word_eol [ 2 ] ) ;
else
snprintf ( tbuf , 512 , " DCC SEND %s " , word_eol [ 2 ] ) ;
handle_command ( sess , tbuf , FALSE ) ;
return TRUE ;
}
static int
cmd_setcursor ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int delta = FALSE ;
if ( * word [ 2 ] )
{
if ( word [ 2 ] [ 0 ] = = ' - ' | | word [ 2 ] [ 0 ] = = ' + ' )
delta = TRUE ;
fe_set_inputbox_cursor ( sess , delta , atoi ( word [ 2 ] ) ) ;
return TRUE ;
}
return FALSE ;
}
static int
cmd_settab ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( * word_eol [ 2 ] )
{
strcpy ( tbuf , sess - > channel ) ;
safe_strcpy ( sess - > channel , word_eol [ 2 ] , CHANLEN ) ;
fe_set_channel ( sess ) ;
strcpy ( sess - > channel , tbuf ) ;
}
return TRUE ;
}
static int
cmd_settext ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
fe_set_inputbox_contents ( sess , word_eol [ 2 ] ) ;
return TRUE ;
}
static int
cmd_splay ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( * word [ 2 ] )
{
sound_play ( word [ 2 ] , FALSE ) ;
return TRUE ;
}
return FALSE ;
}
static int
parse_irc_url ( char * url , char * server_name [ ] , char * port [ ] , char * channel [ ] , int * use_ssl )
{
char * co ;
# ifdef USE_OPENSSL
if ( strncasecmp ( " ircs:// " , url , 7 ) = = 0 )
{
* use_ssl = TRUE ;
* server_name = url + 7 ;
goto urlserv ;
}
# endif
if ( strncasecmp ( " irc:// " , url , 6 ) = = 0 )
{
* server_name = url + 6 ;
# ifdef USE_OPENSSL
urlserv :
# endif
/* check for port */
co = strchr ( * server_name , ' : ' ) ;
if ( co )
{
* port = co + 1 ;
* co = 0 ;
} else
co = * server_name ;
/* check for channel - mirc style */
co = strchr ( co + 1 , ' / ' ) ;
if ( co )
{
* co = 0 ;
co + + ;
if ( * co = = ' # ' )
* channel = co + 1 ;
else
* channel = co ;
}
return TRUE ;
}
return FALSE ;
}
static int
cmd_server ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int offset = 0 ;
char * server_name = NULL ;
char * port = NULL ;
char * pass = NULL ;
char * channel = NULL ;
int use_ssl = FALSE ;
int is_url = TRUE ;
server * serv = sess - > server ;
# ifdef USE_OPENSSL
/* BitchX uses -ssl, mIRC uses -e, let's support both */
if ( strcmp ( word [ 2 ] , " -ssl " ) = = 0 | | strcmp ( word [ 2 ] , " -e " ) = = 0 )
{
use_ssl = TRUE ;
offset + + ; /* args move up by 1 word */
}
# endif
if ( ! parse_irc_url ( word [ 2 + offset ] , & server_name , & port , & channel , & use_ssl ) )
{
is_url = FALSE ;
server_name = word [ 2 + offset ] ;
}
if ( port )
pass = word [ 3 + offset ] ;
else
{
port = word [ 3 + offset ] ;
pass = word [ 4 + offset ] ;
}
if ( ! ( * server_name ) )
return FALSE ;
sess - > server - > network = NULL ;
/* dont clear it for /servchan */
if ( strncasecmp ( word_eol [ 1 ] , " SERVCHAN " , 9 ) )
sess - > willjoinchannel [ 0 ] = 0 ;
if ( channel )
{
sess - > willjoinchannel [ 0 ] = ' # ' ;
safe_strcpy ( ( sess - > willjoinchannel + 1 ) , channel , ( CHANLEN - 1 ) ) ;
}
/* support +7000 style ports like mIRC */
if ( port [ 0 ] = = ' + ' )
{
port + + ;
# ifdef USE_OPENSSL
use_ssl = TRUE ;
# endif
}
if ( * pass )
{
safe_strcpy ( serv - > password , pass , sizeof ( serv - > password ) ) ;
}
# ifdef USE_OPENSSL
serv - > use_ssl = use_ssl ;
serv - > accept_invalid_cert = TRUE ;
# endif
/* try to connect by Network name */
if ( servlist_connect_by_netname ( sess , server_name , ! is_url ) )
return TRUE ;
if ( * port )
{
serv - > connect ( serv , server_name , atoi ( port ) , FALSE ) ;
} else
{
/* -1 for default port */
serv - > connect ( serv , server_name , - 1 , FALSE ) ;
}
/* try to associate this connection with a listed network */
if ( ! serv - > network )
/* search for this hostname in the entire server list */
serv - > network = servlist_net_find_from_server ( server_name ) ;
/* may return NULL, but that's OK */
return TRUE ;
}
static int
cmd_servchan ( struct session * sess , char * tbuf , char * word [ ] ,
char * word_eol [ ] )
{
int offset = 0 ;
# ifdef USE_OPENSSL
if ( strcmp ( word [ 2 ] , " -ssl " ) = = 0 )
offset + + ;
# endif
if ( * word [ 4 + offset ] )
{
safe_strcpy ( sess - > willjoinchannel , word [ 4 + offset ] , CHANLEN ) ;
return cmd_server ( sess , tbuf , word , word_eol ) ;
}
return FALSE ;
}
static int
cmd_topic ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( word [ 2 ] [ 0 ] & & is_channel ( sess - > server , word [ 2 ] ) )
sess - > server - > p_topic ( sess - > server , word [ 2 ] , word_eol [ 3 ] ) ;
else
sess - > server - > p_topic ( sess - > server , sess - > channel , word_eol [ 2 ] ) ;
return TRUE ;
}
static int
cmd_tray ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( strcmp ( word [ 2 ] , " -b " ) = = 0 )
{
fe_tray_set_balloon ( word [ 3 ] , word [ 4 ] [ 0 ] ? word [ 4 ] : NULL ) ;
return TRUE ;
}
if ( strcmp ( word [ 2 ] , " -t " ) = = 0 )
{
fe_tray_set_tooltip ( word [ 3 ] [ 0 ] ? word [ 3 ] : NULL ) ;
return TRUE ;
}
if ( strcmp ( word [ 2 ] , " -i " ) = = 0 )
{
fe_tray_set_icon ( atoi ( word [ 3 ] ) ) ;
return TRUE ;
}
if ( strcmp ( word [ 2 ] , " -f " ) ! = 0 )
return FALSE ;
if ( ! word [ 3 ] [ 0 ] )
{
fe_tray_set_file ( NULL ) ; /* default xchat icon */
return TRUE ;
}
if ( ! word [ 4 ] [ 0 ] )
{
fe_tray_set_file ( word [ 3 ] ) ; /* fixed custom icon */
return TRUE ;
}
/* flash between 2 icons */
fe_tray_set_flash ( word [ 4 ] , word [ 5 ] [ 0 ] ? word [ 5 ] : NULL , atoi ( word [ 3 ] ) ) ;
return TRUE ;
}
static int
cmd_unignore ( struct session * sess , char * tbuf , char * word [ ] ,
char * word_eol [ ] )
{
char * mask = word [ 2 ] ;
char * arg = word [ 3 ] ;
if ( * mask )
{
if ( ignore_del ( mask , NULL ) )
{
if ( strcasecmp ( arg , " QUIET " ) )
EMIT_SIGNAL ( XP_TE_IGNOREREMOVE , sess , mask , NULL , NULL , NULL , 0 ) ;
}
return TRUE ;
}
return FALSE ;
}
static int
cmd_unload ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
# ifdef USE_PLUGIN
int len , by_file = FALSE ;
len = strlen ( word [ 2 ] ) ;
# ifdef WIN32
if ( len > 4 & & strcasecmp ( word [ 2 ] + len - 4 , " .dll " ) = = 0 )
# else
# if defined(__hpux)
if ( len > 3 & & strcasecmp ( word [ 2 ] + len - 3 , " .sl " ) = = 0 )
# else
if ( len > 3 & & strcasecmp ( word [ 2 ] + len - 3 , " .so " ) = = 0 )
# endif
# endif
by_file = TRUE ;
switch ( plugin_kill ( word [ 2 ] , by_file ) )
{
case 0 :
PrintText ( sess , _ ( " No such plugin found. \n " ) ) ;
break ;
case 1 :
return TRUE ;
case 2 :
PrintText ( sess , _ ( " That plugin is refusing to unload. \n " ) ) ;
break ;
}
# endif
return FALSE ;
}
static server *
find_server_from_hostname ( char * hostname )
{
GSList * list = serv_list ;
server * serv ;
while ( list )
{
serv = list - > data ;
if ( ! strcasecmp ( hostname , serv - > hostname ) & & serv - > connected )
return serv ;
list = list - > next ;
}
return NULL ;
}
static server *
find_server_from_net ( void * net )
{
GSList * list = serv_list ;
server * serv ;
while ( list )
{
serv = list - > data ;
if ( serv - > network = = net & & serv - > connected )
return serv ;
list = list - > next ;
}
return NULL ;
}
static void
url_join_only ( server * serv , char * tbuf , char * channel )
{
/* already connected, JOIN only. FIXME: support keys? */
tbuf [ 0 ] = ' # ' ;
/* tbuf is 4kb */
safe_strcpy ( ( tbuf + 1 ) , channel , 256 ) ;
serv - > p_join ( serv , tbuf , " " ) ;
}
static int
cmd_url ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
if ( word [ 2 ] [ 0 ] )
{
char * server_name = NULL ;
char * port = NULL ;
char * channel = NULL ;
char * url = g_strdup ( word [ 2 ] ) ;
int use_ssl = FALSE ;
void * net ;
server * serv ;
if ( parse_irc_url ( url , & server_name , & port , & channel , & use_ssl ) )
{
/* maybe we're already connected to this net */
/* check for "FreeNode" */
net = servlist_net_find ( server_name , NULL , strcasecmp ) ;
/* check for "irc.eu.freenode.net" */
if ( ! net )
net = servlist_net_find_from_server ( server_name ) ;
if ( net )
{
/* found the network, but are we connected? */
serv = find_server_from_net ( net ) ;
if ( serv )
{
url_join_only ( serv , tbuf , channel ) ;
g_free ( url ) ;
return TRUE ;
}
}
else
{
/* an un-listed connection */
serv = find_server_from_hostname ( server_name ) ;
if ( serv )
{
url_join_only ( serv , tbuf , channel ) ;
g_free ( url ) ;
return TRUE ;
}
}
/* not connected to this net, open new window */
cmd_newserver ( sess , tbuf , word , word_eol ) ;
} else
fe_open_url ( word [ 2 ] ) ;
g_free ( url ) ;
return TRUE ;
}
return FALSE ;
}
static int
userlist_cb ( struct User * user , session * sess )
{
time_t lt ;
if ( ! user - > lasttalk )
lt = 0 ;
else
lt = time ( 0 ) - user - > lasttalk ;
PrintTextf ( sess ,
" \003 06%s \t \003 14[ \003 10%-38s \003 14] \017 ov \003 3= \017 %d%d away=%u lt \003 3= \017 %d \n " ,
user - > nick , user - > hostname , user - > op , user - > voice , user - > away , lt ) ;
return TRUE ;
}
static int
cmd_uselect ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int idx = 2 ;
int clear = TRUE ;
int scroll = FALSE ;
if ( strcmp ( word [ 2 ] , " -a " ) = = 0 ) /* ADD (don't clear selections) */
{
clear = FALSE ;
idx + + ;
}
if ( strcmp ( word [ idx ] , " -s " ) = = 0 ) /* SCROLL TO */
{
scroll = TRUE ;
idx + + ;
}
/* always valid, no args means clear the selection list */
fe_uselect ( sess , word + idx , clear , scroll ) ;
return TRUE ;
}
static int
cmd_userlist ( struct session * sess , char * tbuf , char * word [ ] ,
char * word_eol [ ] )
{
tree_foreach ( sess - > usertree , ( tree_traverse_func * ) userlist_cb , sess ) ;
return TRUE ;
}
static int
wallchop_cb ( struct User * user , multidata * data )
{
if ( user - > op )
{
if ( data - > i )
strcat ( data - > tbuf , " , " ) ;
strcat ( data - > tbuf , user - > nick ) ;
data - > i + + ;
}
if ( data - > i = = 5 )
{
data - > i = 0 ;
sprintf ( data - > tbuf + strlen ( data - > tbuf ) ,
" :[@%s] %s " , data - > sess - > channel , data - > reason ) ;
data - > sess - > server - > p_raw ( data - > sess - > server , data - > tbuf ) ;
strcpy ( data - > tbuf , " NOTICE " ) ;
}
return TRUE ;
}
static int
cmd_wallchop ( struct session * sess , char * tbuf , char * word [ ] ,
char * word_eol [ ] )
{
multidata data ;
if ( ! ( * word_eol [ 2 ] ) )
return FALSE ;
strcpy ( tbuf , " NOTICE " ) ;
data . reason = word_eol [ 2 ] ;
data . tbuf = tbuf ;
data . i = 0 ;
data . sess = sess ;
tree_foreach ( sess - > usertree , ( tree_traverse_func * ) wallchop_cb , & data ) ;
if ( data . i )
{
sprintf ( tbuf + strlen ( tbuf ) ,
" :[@%s] %s " , sess - > channel , word_eol [ 2 ] ) ;
sess - > server - > p_raw ( sess - > server , tbuf ) ;
}
return TRUE ;
}
static int
cmd_wallchan ( struct session * sess , char * tbuf , char * word [ ] ,
char * word_eol [ ] )
{
GSList * list ;
if ( * word_eol [ 2 ] )
{
list = sess_list ;
while ( list )
{
sess = list - > data ;
if ( sess - > type = = SESS_CHANNEL )
{
inbound_chanmsg ( sess - > server , NULL , sess - > channel ,
sess - > server - > nick , word_eol [ 2 ] , TRUE , FALSE ) ;
sess - > server - > p_message ( sess - > server , sess - > channel , word_eol [ 2 ] ) ;
}
list = list - > next ;
}
return TRUE ;
}
return FALSE ;
}
static int
cmd_hop ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int i = 2 ;
while ( 1 )
{
if ( ! * word [ i ] )
{
if ( i = = 2 )
return FALSE ;
send_channel_modes ( sess , tbuf , word , 2 , i , ' + ' , ' h ' , 0 ) ;
return TRUE ;
}
i + + ;
}
}
static int
cmd_voice ( struct session * sess , char * tbuf , char * word [ ] , char * word_eol [ ] )
{
int i = 2 ;
while ( 1 )
{
if ( ! * word [ i ] )
{
if ( i = = 2 )
return FALSE ;
send_channel_modes ( sess , tbuf , word , 2 , i , ' + ' , ' v ' , 0 ) ;
return TRUE ;
}
i + + ;
}
}
/* *MUST* be kept perfectly sorted for the bsearch to work */
const struct commands xc_cmds [ ] = {
{ " ADDBUTTON " , cmd_addbutton , 0 , 0 , 1 ,
N_ ( " ADDBUTTON <name> <action>, adds a button under the user-list " ) } ,
{ " ALLCHAN " , cmd_allchannels , 0 , 0 , 1 ,
N_ ( " ALLCHAN <cmd>, sends a command to all channels you're in " ) } ,
{ " ALLCHANL " , cmd_allchannelslocal , 0 , 0 , 1 ,
N_ ( " ALLCHANL <cmd>, sends a command to all channels you're in " ) } ,
{ " ALLSERV " , cmd_allservers , 0 , 0 , 1 ,
N_ ( " ALLSERV <cmd>, sends a command to all servers you're in " ) } ,
{ " AWAY " , cmd_away , 1 , 0 , 1 , N_ ( " AWAY [<reason>], sets you away " ) } ,
{ " BACK " , cmd_back , 1 , 0 , 1 , N_ ( " BACK, sets you back (not away) " ) } ,
{ " BAN " , cmd_ban , 1 , 1 , 1 ,
N_ ( " BAN <mask> [<bantype>], bans everyone matching the mask from the current channel. If they are already on the channel this doesn't kick them (needs chanop) " ) } ,
{ " CHANOPT " , cmd_chanopt , 0 , 0 , 1 , N_ ( " CHANOPT [-quiet] <variable> [<value>] " ) } ,
{ " CHARSET " , cmd_charset , 0 , 0 , 1 , 0 } ,
{ " CLEAR " , cmd_clear , 0 , 0 , 1 , N_ ( " CLEAR [ALL|HISTORY], Clears the current text window or command history " ) } ,
{ " CLOSE " , cmd_close , 0 , 0 , 1 , N_ ( " CLOSE, Closes the current window/tab " ) } ,
{ " COUNTRY " , cmd_country , 0 , 0 , 1 ,
N_ ( " COUNTRY [-s] <code|wildcard>, finds a country code, eg: au = australia " ) } ,
{ " CTCP " , cmd_ctcp , 1 , 0 , 1 ,
N_ ( " CTCP <nick> <message>, send the CTCP message to nick, common messages are VERSION and USERINFO " ) } ,
{ " CYCLE " , cmd_cycle , 1 , 1 , 1 ,
N_ ( " CYCLE [<channel>], parts the current or given channel and immediately rejoins " ) } ,
{ " DCC " , cmd_dcc , 0 , 0 , 1 ,
N_ ( " \n "
" DCC GET <nick> - accept an offered file \n "
" DCC SEND [-maxcps=#] <nick> [file] - send a file to someone \n "
" DCC PSEND [-maxcps=#] <nick> [file] - send a file using passive mode \n "
" DCC LIST - show DCC list \n "
" DCC CHAT <nick> - offer DCC CHAT to someone \n "
" DCC PCHAT <nick> - offer DCC CHAT using passive mode \n "
" DCC CLOSE <type> <nick> <file> example: \n "
" /dcc close send johnsmith file.tar.gz " ) } ,
{ " DEBUG " , cmd_debug , 0 , 0 , 1 , 0 } ,
{ " DEHOP " , cmd_dehop , 1 , 1 , 1 ,
N_ ( " DEHOP <nick>, removes chanhalf-op status from the nick on the current channel (needs chanop) " ) } ,
{ " DELBUTTON " , cmd_delbutton , 0 , 0 , 1 ,
N_ ( " DELBUTTON <name>, deletes a button from under the user-list " ) } ,
{ " DEOP " , cmd_deop , 1 , 1 , 1 ,
N_ ( " DEOP <nick>, removes chanop status from the nick on the current channel (needs chanop) " ) } ,
{ " DEVOICE " , cmd_devoice , 1 , 1 , 1 ,
N_ ( " DEVOICE <nick>, removes voice status from the nick on the current channel (needs chanop) " ) } ,
{ " DISCON " , cmd_discon , 0 , 0 , 1 , N_ ( " DISCON, Disconnects from server " ) } ,
{ " DNS " , cmd_dns , 0 , 0 , 1 , N_ ( " DNS <nick|host|ip>, Finds a users IP number " ) } ,
{ " ECHO " , cmd_echo , 0 , 0 , 1 , N_ ( " ECHO <text>, Prints text locally " ) } ,
# ifndef WIN32
{ " EXEC " , cmd_exec , 0 , 0 , 1 ,
N_ ( " EXEC [-o] <command>, runs the command. If -o flag is used then output is sent to current channel, else is printed to current text box " ) } ,
# ifndef __EMX__
{ " EXECCONT " , cmd_execc , 0 , 0 , 1 , N_ ( " EXECCONT, sends the process SIGCONT " ) } ,
# endif
{ " EXECKILL " , cmd_execk , 0 , 0 , 1 ,
N_ ( " EXECKILL [-9], kills a running exec in the current session. If -9 is given the process is SIGKILL'ed " ) } ,
# ifndef __EMX__
{ " EXECSTOP " , cmd_execs , 0 , 0 , 1 , N_ ( " EXECSTOP, sends the process SIGSTOP " ) } ,
{ " EXECWRITE " , cmd_execw , 0 , 0 , 1 , N_ ( " EXECWRITE, sends data to the processes stdin " ) } ,
# endif
# endif
{ " FLUSHQ " , cmd_flushq , 0 , 0 , 1 ,
N_ ( " FLUSHQ, flushes the current server's send queue " ) } ,
{ " GATE " , cmd_gate , 0 , 0 , 1 ,
N_ ( " GATE <host> [<port>], proxies through a host, port defaults to 23 " ) } ,
{ " GETFILE " , cmd_getfile , 0 , 0 , 1 , " GETFILE [-folder] [-multi] [-save] <command> <title> [<initial>] " } ,
{ " GETINT " , cmd_getint , 0 , 0 , 1 , " GETINT <default> <command> <prompt> " } ,
{ " GETSTR " , cmd_getstr , 0 , 0 , 1 , " GETSTR <default> <command> <prompt> " } ,
{ " GHOST " , cmd_ghost , 1 , 0 , 1 , N_ ( " GHOST <nick> [password], Kills a ghosted nickname " ) } ,
{ " GUI " , cmd_gui , 0 , 0 , 1 , " GUI [APPLY|ATTACH|DETACH|SHOW|HIDE|FOCUS|FLASH|ICONIFY|COLOR <n>] \n "
" GUI [MSGBOX <text>|MENU TOGGLE] " } ,
{ " HELP " , cmd_help , 0 , 0 , 1 , 0 } ,
{ " HOP " , cmd_hop , 1 , 1 , 1 ,
N_ ( " HOP <nick>, gives chanhalf-op status to the nick (needs chanop) " ) } ,
{ " ID " , cmd_id , 1 , 0 , 1 , N_ ( " ID <password>, identifies yourself to nickserv " ) } ,
{ " IGNORE " , cmd_ignore , 0 , 0 , 1 ,
N_ ( " IGNORE <mask> <types..> <options..> \n "
" mask - host mask to ignore, eg: *!*@*.aol.com \n "
" types - types of data to ignore, one or all of: \n "
" PRIV, CHAN, NOTI, CTCP, DCC, INVI, ALL \n "
" options - NOSAVE, QUIET " ) } ,
{ " INVITE " , cmd_invite , 1 , 0 , 1 ,
N_ ( " INVITE <nick> [<channel>], invites someone to a channel, by default the current channel (needs chanop) " ) } ,
{ " JOIN " , cmd_join , 1 , 0 , 0 , N_ ( " JOIN <channel>, joins the channel " ) } ,
{ " KICK " , cmd_kick , 1 , 1 , 1 ,
N_ ( " KICK <nick>, kicks the nick from the current channel (needs chanop) " ) } ,
{ " KICKBAN " , cmd_kickban , 1 , 1 , 1 ,
N_ ( " KICKBAN <nick>, bans then kicks the nick from the current channel (needs chanop) " ) } ,
{ " KILLALL " , cmd_killall , 0 , 0 , 1 , " KILLALL, immediately exit " } ,
{ " LAGCHECK " , cmd_lagcheck , 0 , 0 , 1 ,
N_ ( " LAGCHECK, forces a new lag check " ) } ,
{ " LASTLOG " , cmd_lastlog , 0 , 0 , 1 ,
N_ ( " LASTLOG <string>, searches for a string in the buffer " ) } ,
{ " LIST " , cmd_list , 1 , 0 , 1 , 0 } ,
{ " LOAD " , cmd_load , 0 , 0 , 1 , N_ ( " LOAD [-e] <file>, loads a plugin or script " ) } ,
{ " MDEHOP " , cmd_mdehop , 1 , 1 , 1 ,
N_ ( " MDEHOP, Mass deop's all chanhalf-ops in the current channel (needs chanop) " ) } ,
{ " MDEOP " , cmd_mdeop , 1 , 1 , 1 ,
N_ ( " MDEOP, Mass deop's all chanops in the current channel (needs chanop) " ) } ,
{ " ME " , cmd_me , 0 , 0 , 1 ,
N_ ( " ME <action>, sends the action to the current channel (actions are written in the 3rd person, like /me jumps) " ) } ,
{ " MENU " , cmd_menu , 0 , 0 , 1 , " MENU [-eX] [-i<ICONFILE>] [-k<mod>,<key>] [-m] [-pX] [-r<X,group>] [-tX] {ADD|DEL} <path> [command] [unselect command] \n "
" See http://xchat.org/docs/menu/ for more details. " } ,
{ " MKICK " , cmd_mkick , 1 , 1 , 1 ,
N_ ( " MKICK, Mass kicks everyone except you in the current channel (needs chanop) " ) } ,
{ " MODE " , cmd_mode , 1 , 0 , 1 , 0 } ,
{ " MOP " , cmd_mop , 1 , 1 , 1 ,
N_ ( " MOP, Mass op's all users in the current channel (needs chanop) " ) } ,
{ " MSG " , cmd_msg , 0 , 0 , 1 , N_ ( " MSG <nick> <message>, sends a private message " ) } ,
{ " NAMES " , cmd_names , 1 , 0 , 1 ,
N_ ( " NAMES, Lists the nicks on the current channel " ) } ,
{ " NCTCP " , cmd_nctcp , 1 , 0 , 1 ,
N_ ( " NCTCP <nick> <message>, Sends a CTCP notice " ) } ,
{ " NEWSERVER " , cmd_newserver , 0 , 0 , 1 , N_ ( " NEWSERVER [-noconnect] <hostname> [<port>] " ) } ,
{ " NICK " , cmd_nick , 0 , 0 , 1 , N_ ( " NICK <nickname>, sets your nick " ) } ,
{ " NOTICE " , cmd_notice , 1 , 0 , 1 ,
N_ ( " NOTICE <nick/channel> <message>, sends a notice. Notices are a type of message that should be auto reacted to " ) } ,
{ " NOTIFY " , cmd_notify , 0 , 0 , 1 ,
N_ ( " NOTIFY [-n network1[,network2,...]] [<nick>], displays your notify list or adds someone to it " ) } ,
{ " OP " , cmd_op , 1 , 1 , 1 ,
N_ ( " OP <nick>, gives chanop status to the nick (needs chanop) " ) } ,
{ " PART " , cmd_part , 1 , 1 , 0 ,
N_ ( " PART [<channel>] [<reason>], leaves the channel, by default the current one " ) } ,
{ " PING " , cmd_ping , 1 , 0 , 1 ,
N_ ( " PING <nick | channel>, CTCP pings nick or channel " ) } ,
{ " QUERY " , cmd_query , 0 , 0 , 1 ,
N_ ( " QUERY [-nofocus] <nick>, opens up a new privmsg window to someone " ) } ,
{ " QUIT " , cmd_quit , 0 , 0 , 1 ,
N_ ( " QUIT [<reason>], disconnects from the current server " ) } ,
{ " QUOTE " , cmd_quote , 1 , 0 , 1 ,
N_ ( " QUOTE <text>, sends the text in raw form to the server " ) } ,
# ifdef USE_OPENSSL
{ " RECONNECT " , cmd_reconnect , 0 , 0 , 1 ,
N_ ( " RECONNECT [-ssl] [<host>] [<port>] [<password>], Can be called just as /RECONNECT to reconnect to the current server or with /RECONNECT ALL to reconnect to all the open servers " ) } ,
# else
{ " RECONNECT " , cmd_reconnect , 0 , 0 , 1 ,
N_ ( " RECONNECT [<host>] [<port>] [<password>], Can be called just as /RECONNECT to reconnect to the current server or with /RECONNECT ALL to reconnect to all the open servers " ) } ,
# endif
{ " RECV " , cmd_recv , 1 , 0 , 1 , N_ ( " RECV <text>, send raw data to xchat, as if it was received from the irc server " ) } ,
2011-09-07 16:08:24 -04:00
{ " SAVECONF " , cmd_saveconf , 0 , 0 , 1 , N_ ( " SAVECONF, saves the current settings to disk " ) } ,
2011-02-23 22:14:30 -05:00
{ " SAY " , cmd_say , 0 , 0 , 1 ,
N_ ( " SAY <text>, sends the text to the object in the current window " ) } ,
{ " SEND " , cmd_send , 0 , 0 , 1 , N_ ( " SEND <nick> [<file>] " ) } ,
# ifdef USE_OPENSSL
{ " SERVCHAN " , cmd_servchan , 0 , 0 , 1 ,
N_ ( " SERVCHAN [-ssl] <host> <port> <channel>, connects and joins a channel " ) } ,
# else
{ " SERVCHAN " , cmd_servchan , 0 , 0 , 1 ,
N_ ( " SERVCHAN <host> <port> <channel>, connects and joins a channel " ) } ,
# endif
# ifdef USE_OPENSSL
{ " SERVER " , cmd_server , 0 , 0 , 1 ,
N_ ( " SERVER [-ssl] <host> [<port>] [<password>], connects to a server, the default port is 6667 for normal connections, and 9999 for ssl connections " ) } ,
# else
{ " SERVER " , cmd_server , 0 , 0 , 1 ,
N_ ( " SERVER <host> [<port>] [<password>], connects to a server, the default port is 6667 " ) } ,
# endif
{ " SET " , cmd_set , 0 , 0 , 1 , N_ ( " SET [-e] [-off|-on] [-quiet] <variable> [<value>] " ) } ,
{ " SETCURSOR " , cmd_setcursor , 0 , 0 , 1 , N_ ( " SETCURSOR [-|+]<position> " ) } ,
{ " SETTAB " , cmd_settab , 0 , 0 , 1 , 0 } ,
{ " SETTEXT " , cmd_settext , 0 , 0 , 1 , 0 } ,
{ " SPLAY " , cmd_splay , 0 , 0 , 1 , " SPLAY <soundfile> " } ,
{ " TOPIC " , cmd_topic , 1 , 1 , 1 ,
N_ ( " TOPIC [<topic>], sets the topic if one is given, else shows the current topic " ) } ,
{ " TRAY " , cmd_tray , 0 , 0 , 1 ,
N_ ( " \n TRAY -f <timeout> <file1> [<file2>] Blink tray between two icons. \n "
" TRAY -f <filename> Set tray to a fixed icon. \n "
" TRAY -i <number> Blink tray with an internal icon. \n "
" TRAY -t <text> Set the tray tooltip. \n "
" TRAY -b <title> <text> Set the tray balloon. "
) } ,
{ " UNBAN " , cmd_unban , 1 , 1 , 1 ,
N_ ( " UNBAN <mask> [<mask>...], unbans the specified masks. " ) } ,
{ " UNIGNORE " , cmd_unignore , 0 , 0 , 1 , N_ ( " UNIGNORE <mask> [QUIET] " ) } ,
{ " UNLOAD " , cmd_unload , 0 , 0 , 1 , N_ ( " UNLOAD <name>, unloads a plugin or script " ) } ,
{ " URL " , cmd_url , 0 , 0 , 1 , N_ ( " URL <url>, opens a URL in your browser " ) } ,
{ " USELECT " , cmd_uselect , 0 , 1 , 0 ,
N_ ( " USELECT [-a] [-s] <nick1> <nick2> etc, highlights nick(s) in channel userlist " ) } ,
{ " USERLIST " , cmd_userlist , 1 , 1 , 1 , 0 } ,
{ " VOICE " , cmd_voice , 1 , 1 , 1 ,
N_ ( " VOICE <nick>, gives voice status to someone (needs chanop) " ) } ,
{ " WALLCHAN " , cmd_wallchan , 1 , 1 , 1 ,
N_ ( " WALLCHAN <message>, writes the message to all channels " ) } ,
{ " WALLCHOP " , cmd_wallchop , 1 , 1 , 1 ,
N_ ( " WALLCHOP <message>, sends the message to all chanops on the current channel " ) } ,
{ 0 , 0 , 0 , 0 , 0 , 0 }
} ;
static int
command_compare ( const void * a , const void * b )
{
return strcasecmp ( a , ( ( struct commands * ) b ) - > name ) ;
}
static struct commands *
find_internal_command ( char * name )
{
/* the "-1" is to skip the NULL terminator */
return bsearch ( name , xc_cmds , ( sizeof ( xc_cmds ) /
sizeof ( xc_cmds [ 0 ] ) ) - 1 , sizeof ( xc_cmds [ 0 ] ) , command_compare ) ;
}
static void
help ( session * sess , char * tbuf , char * helpcmd , int quiet )
{
struct commands * cmd ;
if ( plugin_show_help ( sess , helpcmd ) )
return ;
cmd = find_internal_command ( helpcmd ) ;
if ( cmd )
{
if ( cmd - > help )
{
snprintf ( tbuf , TBUFSIZE , _ ( " Usage: %s \n " ) , _ ( cmd - > help ) ) ;
PrintText ( sess , tbuf ) ;
} else
{
if ( ! quiet )
PrintText ( sess , _ ( " \n No help available on that command. \n " ) ) ;
}
return ;
}
if ( ! quiet )
PrintText ( sess , _ ( " No such command. \n " ) ) ;
}
/* inserts %a, %c, %d etc into buffer. Also handles &x %x for word/word_eol. *
* returns 2 on buffer overflow
* returns 1 on success *
* returns 0 on bad - args - for - user - command *
* - word / word_eol args might be NULL *
* - this beast is used for UserCommands , UserlistButtons and CTCP replies */
int
auto_insert ( char * dest , int destlen , unsigned char * src , char * word [ ] ,
char * word_eol [ ] , char * a , char * c , char * d , char * e , char * h ,
char * n , char * s )
{
int num ;
char buf [ 32 ] ;
time_t now ;
struct tm * tm_ptr ;
char * utf ;
gsize utf_len ;
char * orig = dest ;
destlen - - ;
while ( src [ 0 ] )
{
if ( src [ 0 ] = = ' % ' | | src [ 0 ] = = ' & ' )
{
if ( isdigit ( ( unsigned char ) src [ 1 ] ) )
{
if ( isdigit ( ( unsigned char ) src [ 2 ] ) & & isdigit ( ( unsigned char ) src [ 3 ] ) )
{
buf [ 0 ] = src [ 1 ] ;
buf [ 1 ] = src [ 2 ] ;
buf [ 2 ] = src [ 3 ] ;
buf [ 3 ] = 0 ;
dest [ 0 ] = atoi ( buf ) ;
utf = g_locale_to_utf8 ( dest , 1 , 0 , & utf_len , 0 ) ;
if ( utf )
{
if ( ( dest - orig ) + utf_len > = destlen )
{
g_free ( utf ) ;
return 2 ;
}
memcpy ( dest , utf , utf_len ) ;
g_free ( utf ) ;
dest + = utf_len ;
}
src + = 3 ;
} else
{
if ( word )
{
src + + ;
num = src [ 0 ] - ' 0 ' ; /* ascii to decimal */
if ( * word [ num ] = = 0 )
return 0 ;
if ( src [ - 1 ] = = ' % ' )
utf = word [ num ] ;
else
utf = word_eol [ num ] ;
/* avoid recusive usercommand overflow */
if ( ( dest - orig ) + strlen ( utf ) > = destlen )
return 2 ;
strcpy ( dest , utf ) ;
dest + = strlen ( dest ) ;
}
}
} else
{
if ( src [ 0 ] = = ' & ' )
goto lamecode ;
src + + ;
utf = NULL ;
switch ( src [ 0 ] )
{
case ' % ' :
if ( ( dest - orig ) + 2 > = destlen )
return 2 ;
dest [ 0 ] = ' % ' ;
dest [ 1 ] = 0 ;
dest + + ;
break ;
case ' a ' :
utf = a ; break ;
case ' c ' :
utf = c ; break ;
case ' d ' :
utf = d ; break ;
case ' e ' :
utf = e ; break ;
case ' h ' :
utf = h ; break ;
case ' m ' :
utf = get_cpu_str ( ) ; break ;
case ' n ' :
utf = n ; break ;
case ' s ' :
utf = s ; break ;
case ' t ' :
now = time ( 0 ) ;
utf = ctime ( & now ) ;
utf [ 19 ] = 0 ;
break ;
case ' v ' :
utf = PACKAGE_VERSION ; break ;
break ;
case ' y ' :
now = time ( 0 ) ;
tm_ptr = localtime ( & now ) ;
snprintf ( buf , sizeof ( buf ) , " %4d%02d%02d " , 1900 +
tm_ptr - > tm_year , 1 + tm_ptr - > tm_mon , tm_ptr - > tm_mday ) ;
utf = buf ;
break ;
default :
src - - ;
goto lamecode ;
}
if ( utf )
{
if ( ( dest - orig ) + strlen ( utf ) > = destlen )
return 2 ;
strcpy ( dest , utf ) ;
dest + = strlen ( dest ) ;
}
}
src + + ;
} else
{
utf_len = g_utf8_skip [ src [ 0 ] ] ;
if ( ( dest - orig ) + utf_len > = destlen )
return 2 ;
if ( utf_len = = 1 )
{
lamecode :
dest [ 0 ] = src [ 0 ] ;
dest + + ;
src + + ;
} else
{
memcpy ( dest , src , utf_len ) ;
dest + = utf_len ;
src + = utf_len ;
}
}
}
dest [ 0 ] = 0 ;
return 1 ;
}
void
check_special_chars ( char * cmd , int do_ascii ) /* check for %X */
{
int occur = 0 ;
int len = strlen ( cmd ) ;
char * buf , * utf ;
char tbuf [ 4 ] ;
int i = 0 , j = 0 ;
gsize utf_len ;
if ( ! len )
return ;
buf = malloc ( len + 1 ) ;
if ( buf )
{
while ( cmd [ j ] )
{
switch ( cmd [ j ] )
{
case ' % ' :
occur + + ;
if ( do_ascii & &
j + 3 < len & &
( isdigit ( ( unsigned char ) cmd [ j + 1 ] ) & & isdigit ( ( unsigned char ) cmd [ j + 2 ] ) & &
isdigit ( ( unsigned char ) cmd [ j + 3 ] ) ) )
{
tbuf [ 0 ] = cmd [ j + 1 ] ;
tbuf [ 1 ] = cmd [ j + 2 ] ;
tbuf [ 2 ] = cmd [ j + 3 ] ;
tbuf [ 3 ] = 0 ;
buf [ i ] = atoi ( tbuf ) ;
utf = g_locale_to_utf8 ( buf + i , 1 , 0 , & utf_len , 0 ) ;
if ( utf )
{
memcpy ( buf + i , utf , utf_len ) ;
g_free ( utf ) ;
i + = ( utf_len - 1 ) ;
}
j + = 3 ;
} else
{
switch ( cmd [ j + 1 ] )
{
case ' R ' :
buf [ i ] = ' \026 ' ;
break ;
case ' U ' :
buf [ i ] = ' \037 ' ;
break ;
case ' B ' :
buf [ i ] = ' \002 ' ;
break ;
case ' C ' :
buf [ i ] = ' \003 ' ;
break ;
case ' O ' :
buf [ i ] = ' \017 ' ;
break ;
case ' H ' : /* CL: invisible text code */
buf [ i ] = HIDDEN_CHAR ;
break ;
case ' % ' :
buf [ i ] = ' % ' ;
break ;
default :
buf [ i ] = ' % ' ;
j - - ;
break ;
}
j + + ;
break ;
default :
buf [ i ] = cmd [ j ] ;
}
}
j + + ;
i + + ;
}
buf [ i ] = 0 ;
if ( occur )
strcpy ( cmd , buf ) ;
free ( buf ) ;
}
}
typedef struct
{
char * nick ;
int len ;
struct User * best ;
int bestlen ;
char * space ;
char * tbuf ;
} nickdata ;
static int
nick_comp_cb ( struct User * user , nickdata * data )
{
int lenu ;
if ( ! rfc_ncasecmp ( user - > nick , data - > nick , data - > len ) )
{
lenu = strlen ( user - > nick ) ;
if ( lenu = = data - > len )
{
snprintf ( data - > tbuf , TBUFSIZE , " %s%s " , user - > nick , data - > space ) ;
data - > len = - 1 ;
return FALSE ;
} else if ( lenu < data - > bestlen )
{
data - > bestlen = lenu ;
data - > best = user ;
}
}
return TRUE ;
}
static void
perform_nick_completion ( struct session * sess , char * cmd , char * tbuf )
{
int len ;
char * space = strchr ( cmd , ' ' ) ;
if ( space & & space ! = cmd )
{
if ( space [ - 1 ] = = prefs . nick_suffix [ 0 ] & & space - 1 ! = cmd )
{
len = space - cmd - 1 ;
if ( len < NICKLEN )
{
char nick [ NICKLEN ] ;
nickdata data ;
memcpy ( nick , cmd , len ) ;
nick [ len ] = 0 ;
data . nick = nick ;
data . len = len ;
data . bestlen = INT_MAX ;
data . best = NULL ;
data . tbuf = tbuf ;
data . space = space - 1 ;
tree_foreach ( sess - > usertree , ( tree_traverse_func * ) nick_comp_cb , & data ) ;
if ( data . len = = - 1 )
return ;
if ( data . best )
{
snprintf ( tbuf , TBUFSIZE , " %s%s " , data . best - > nick , space - 1 ) ;
return ;
}
}
}
}
strcpy ( tbuf , cmd ) ;
}
static void
user_command ( session * sess , char * tbuf , char * cmd , char * word [ ] ,
char * word_eol [ ] )
{
if ( ! auto_insert ( tbuf , 2048 , cmd , word , word_eol , " " , sess - > channel , " " ,
server_get_network ( sess - > server , TRUE ) , " " ,
sess - > server - > nick , " " ) )
{
PrintText ( sess , _ ( " Bad arguments for user command. \n " ) ) ;
return ;
}
handle_command ( sess , tbuf , TRUE ) ;
}
/* handle text entered without a CMDchar prefix */
static void
handle_say ( session * sess , char * text , int check_spch )
{
struct DCC * dcc ;
char * word [ PDIWORDS + 1 ] ;
char * word_eol [ PDIWORDS + 1 ] ;
char pdibuf_static [ 1024 ] ;
char newcmd_static [ 1024 ] ;
char * pdibuf = pdibuf_static ;
char * newcmd = newcmd_static ;
int len ;
int newcmdlen = sizeof newcmd_static ;
if ( strcmp ( sess - > channel , " (lastlog) " ) = = 0 )
{
lastlog ( sess - > lastlog_sess , text , sess - > lastlog_regexp ) ;
return ;
}
len = strlen ( text ) ;
if ( len > = sizeof pdibuf_static )
pdibuf = malloc ( len + 1 ) ;
if ( len + NICKLEN > = newcmdlen )
newcmd = malloc ( newcmdlen = len + NICKLEN + 1 ) ;
if ( check_spch & & prefs . perc_color )
check_special_chars ( text , prefs . perc_ascii ) ;
/* Python relies on this */
word [ PDIWORDS ] = NULL ;
word_eol [ PDIWORDS ] = NULL ;
/* split the text into words and word_eol */
process_data_init ( pdibuf , text , word , word_eol , TRUE , FALSE ) ;
/* a command of "" can be hooked for non-commands */
if ( plugin_emit_command ( sess , " " , word , word_eol ) )
goto xit ;
/* incase a plugin did /close */
if ( ! is_session ( sess ) )
goto xit ;
if ( ! sess - > channel [ 0 ] | | sess - > type = = SESS_SERVER | | sess - > type = = SESS_NOTICES | | sess - > type = = SESS_SNOTICES )
{
notj_msg ( sess ) ;
goto xit ;
}
if ( prefs . nickcompletion )
perform_nick_completion ( sess , text , newcmd ) ;
else
safe_strcpy ( newcmd , text , newcmdlen ) ;
text = newcmd ;
if ( sess - > type = = SESS_DIALOG )
{
/* try it via dcc, if possible */
dcc = dcc_write_chat ( sess - > channel , text ) ;
if ( dcc )
{
inbound_chanmsg ( sess - > server , NULL , sess - > channel ,
sess - > server - > nick , text , TRUE , FALSE ) ;
set_topic ( sess , net_ip ( dcc - > addr ) , net_ip ( dcc - > addr ) ) ;
goto xit ;
}
}
if ( sess - > server - > connected )
{
unsigned int max ;
unsigned char t = 0 ;
/* maximum allowed message text */
/* :nickname!username@host.com PRIVMSG #channel :text\r\n */
max = 512 ;
max - = 16 ; /* :, !, @, " PRIVMSG ", " ", :, \r, \n */
max - = strlen ( sess - > server - > nick ) ;
max - = strlen ( sess - > channel ) ;
if ( sess - > me & & sess - > me - > hostname )
max - = strlen ( sess - > me - > hostname ) ;
else
{
max - = 9 ; /* username */
max - = 65 ; /* max possible hostname and '@' */
}
if ( strlen ( text ) > max )
{
int i = 0 , size ;
/* traverse the utf8 string and find the nearest cut point that
doesn ' t split 1 char in half */
while ( 1 )
{
size = g_utf8_skip [ ( ( unsigned char * ) text ) [ i ] ] ;
if ( ( i + size ) > = max )
break ;
i + = size ;
}
max = i ;
t = text [ max ] ;
text [ max ] = 0 ; /* insert a NULL terminator to shorten it */
}
inbound_chanmsg ( sess - > server , sess , sess - > channel , sess - > server - > nick ,
text , TRUE , FALSE ) ;
sess - > server - > p_message ( sess - > server , sess - > channel , text ) ;
if ( t )
{
text [ max ] = t ;
handle_say ( sess , text + max , FALSE ) ;
}
} else
{
notc_msg ( sess ) ;
}
xit :
if ( pdibuf ! = pdibuf_static )
free ( pdibuf ) ;
if ( newcmd ! = newcmd_static )
free ( newcmd ) ;
}
/* handle a command, without the '/' prefix */
int
handle_command ( session * sess , char * cmd , int check_spch )
{
struct popup * pop ;
int user_cmd = FALSE ;
GSList * list ;
char * word [ PDIWORDS + 1 ] ;
char * word_eol [ PDIWORDS + 1 ] ;
static int command_level = 0 ;
struct commands * int_cmd ;
char pdibuf_static [ 1024 ] ;
char tbuf_static [ TBUFSIZE ] ;
char * pdibuf ;
char * tbuf ;
int len ;
int ret = TRUE ;
if ( command_level > 99 )
{
fe_message ( _ ( " Too many recursive usercommands, aborting. " ) , FE_MSG_ERROR ) ;
return TRUE ;
}
command_level + + ;
/* anything below MUST DEC command_level before returning */
len = strlen ( cmd ) ;
if ( len > = sizeof ( pdibuf_static ) )
pdibuf = malloc ( len + 1 ) ;
else
pdibuf = pdibuf_static ;
if ( ( len * 2 ) > = sizeof ( tbuf_static ) )
tbuf = malloc ( ( len * 2 ) + 1 ) ;
else
tbuf = tbuf_static ;
/* split the text into words and word_eol */
process_data_init ( pdibuf , cmd , word , word_eol , TRUE , TRUE ) ;
/* ensure an empty string at index 32 for cmd_deop etc */
/* (internal use only, plugins can still only read 1-31). */
word [ PDIWORDS ] = " \000 \000 " ;
word_eol [ PDIWORDS ] = " \000 \000 " ;
int_cmd = find_internal_command ( word [ 1 ] ) ;
/* redo it without quotes processing, for some commands like /JOIN */
if ( int_cmd & & ! int_cmd - > handle_quotes )
process_data_init ( pdibuf , cmd , word , word_eol , FALSE , FALSE ) ;
if ( check_spch & & prefs . perc_color )
check_special_chars ( cmd , prefs . perc_ascii ) ;
if ( plugin_emit_command ( sess , word [ 1 ] , word , word_eol ) )
goto xit ;
/* incase a plugin did /close */
if ( ! is_session ( sess ) )
goto xit ;
/* first see if it's a userCommand */
list = command_list ;
while ( list )
{
pop = ( struct popup * ) list - > data ;
if ( ! strcasecmp ( pop - > name , word [ 1 ] ) )
{
user_command ( sess , tbuf , pop - > cmd , word , word_eol ) ;
user_cmd = TRUE ;
}
list = list - > next ;
}
if ( user_cmd )
goto xit ;
/* now check internal commands */
int_cmd = find_internal_command ( word [ 1 ] ) ;
if ( int_cmd )
{
if ( int_cmd - > needserver & & ! sess - > server - > connected )
{
notc_msg ( sess ) ;
} else if ( int_cmd - > needchannel & & ! sess - > channel [ 0 ] )
{
notj_msg ( sess ) ;
} else
{
switch ( int_cmd - > callback ( sess , tbuf , word , word_eol ) )
{
case FALSE :
help ( sess , tbuf , int_cmd - > name , TRUE ) ;
break ;
case 2 :
ret = FALSE ;
goto xit ;
}
}
} else
{
/* unknown command, just send it to the server and hope */
if ( ! sess - > server - > connected )
PrintText ( sess , _ ( " Unknown Command. Try /help \n " ) ) ;
else
sess - > server - > p_raw ( sess - > server , cmd ) ;
}
xit :
command_level - - ;
if ( pdibuf ! = pdibuf_static )
free ( pdibuf ) ;
if ( tbuf ! = tbuf_static )
free ( tbuf ) ;
return ret ;
}
/* handle one line entered into the input box */
static int
handle_user_input ( session * sess , char * text , int history , int nocommand )
{
if ( * text = = ' \0 ' )
return 1 ;
if ( history )
history_add ( & sess - > history , text ) ;
/* is it NOT a command, just text? */
if ( nocommand | | text [ 0 ] ! = prefs . cmdchar [ 0 ] )
{
handle_say ( sess , text , TRUE ) ;
return 1 ;
}
/* check for // */
if ( text [ 0 ] = = prefs . cmdchar [ 0 ] & & text [ 1 ] = = prefs . cmdchar [ 0 ] )
{
handle_say ( sess , text + 1 , TRUE ) ;
return 1 ;
}
if ( prefs . cmdchar [ 0 ] = = ' / ' )
{
int i ;
const char * unix_dirs [ ] = {
" /bin/ " , " /boot/ " , " /dev/ " ,
" /etc/ " , " /home/ " , " /lib/ " ,
" /lost+found/ " , " /mnt/ " , " /opt/ " ,
" /proc/ " , " /root/ " , " /sbin/ " ,
" /tmp/ " , " /usr/ " , " /var/ " ,
" /gnome/ " , NULL } ;
for ( i = 0 ; unix_dirs [ i ] ! = NULL ; i + + )
if ( strncmp ( text , unix_dirs [ i ] , strlen ( unix_dirs [ i ] ) ) = = 0 )
{
handle_say ( sess , text , TRUE ) ;
return 1 ;
}
}
return handle_command ( sess , text + 1 , TRUE ) ;
}
/* changed by Steve Green. Macs sometimes paste with imbedded \r */
void
handle_multiline ( session * sess , char * cmd , int history , int nocommand )
{
while ( * cmd )
{
char * cr = cmd + strcspn ( cmd , " \n \r " ) ;
int end_of_string = * cr = = 0 ;
* cr = 0 ;
if ( ! handle_user_input ( sess , cmd , history , nocommand ) )
return ;
if ( end_of_string )
break ;
cmd = cr + 1 ;
}
}
/*void
handle_multiline ( session * sess , char * cmd , int history , int nocommand )
{
char * cr ;
cr = strchr ( cmd , ' \n ' ) ;
if ( cr )
{
while ( 1 )
{
if ( cr )
* cr = 0 ;
if ( ! handle_user_input ( sess , cmd , history , nocommand ) )
return ;
if ( ! cr )
break ;
cmd = cr + 1 ;
if ( * cmd = = 0 )
break ;
cr = strchr ( cmd , ' \n ' ) ;
}
} else
{
handle_user_input ( sess , cmd , history , nocommand ) ;
}
} */