📄 alias_command.c
字号:
/* * Copyright (C) 2000 Onlyer (onlyer@263.net) * Copyright (C) 2002 Ross Combs (rocombs@cs.nmsu.edu) * * 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 ALIAS_COMMAND_INTERNAL_ACCESS#include "common/setup_before.h"#ifdef HAVE_STDDEF_H# include <stddef.h>#else# ifndef NULL# define NULL ((void *)0)# endif#endif#ifdef STDC_HEADERS# include <stdlib.h>#else# ifdef HAVE_MALLOC_H# include <malloc.h># endif#endif#ifdef HAVE_STRING_H# include <string.h>#else# ifdef HAVE_STRINGS_H# include <strings.h># endif#endif#include "compat/strcasecmp.h"#include <ctype.h>#include <errno.h>#include "compat/strerror.h"#include "common/field_sizes.h"#include "common/util.h"#include "common/eventlog.h"#include "common/list.h"#include "common/xalloc.h"#include "message.h"#include "connection.h"#include "alias_command.h"#include "common/setup_after.h"static t_list * aliaslist_head=NULL;#define MAX_ALIAS_LEN 32static int list_aliases(t_connection * c);static char * replace_args(char const * in, unsigned int * offsets, int numargs, char const * text);static int do_alias(t_connection * c, char const * cmd, char const * args);static int list_aliases(t_connection * c){ t_elem const * elem1; t_elem const * elem2; t_alias const * alias; t_output * output; char temp[MAX_MESSAGE_LEN]; message_send_text(c,message_type_info,c,"Alias list:"); LIST_TRAVERSE_CONST(aliaslist_head,elem1) { if (!(alias = elem_get_data(elem1))) continue; sprintf(temp,"@%.128s",alias->alias); message_send_text(c,message_type_info,c,temp); LIST_TRAVERSE_CONST(alias->output,elem2) { if (!(output = elem_get_data(elem2))) continue; /* * FIXME: need a more user-friendly way to express this... maybe * add a help line to the file format? */ if (output->min==-1) sprintf(temp,"[*]%.128s",output->line); else if (output->max==-1) sprintf(temp,"[%d+]%.128s",output->min,output->line); else if (output->min == output->max) sprintf(temp,"[%d]%.128s",output->min,output->line); else sprintf(temp,"[%d-%d]%.128s",output->min,output->max,output->line); message_send_text(c,message_type_info,c,temp); } } return 0;}static char * replace_args(char const * in, unsigned int * offsets, int numargs, char const * text){ char * out; unsigned int inpos; unsigned int outpos; unsigned int off1; unsigned int off2; unsigned int size; off1 = off2 = 0; out = xstrdup(in); size = strlen(out); for (inpos=outpos=0; inpos<strlen(in); inpos++) { if (in[inpos]!='$') { out[outpos] = in[inpos]; outpos++; continue; } inpos++; if (in[inpos]=='*') { off1 = offsets[0]; off2 = strlen(text); } else if (in[inpos]=='{') { int arg1, arg2; char symbol; if (sscanf(&in[inpos],"{%u-%u}",&arg1,&arg2)!=2) { if (sscanf(&in[inpos],"{%d%c",&arg2,&symbol)!=2) { while (in[inpos]!='\0' && in[inpos]!='}') inpos++; continue; } else { if (symbol=='}') { if (arg2<0) { arg1 = 0; arg2 = -arg2; } else { arg1 = arg2; } } else if (symbol=='-') { arg1 = arg2; arg2 = numargs-1; } else { while (in[inpos]!='\0' && in[inpos]!='}') inpos++; continue; } } } if (arg2>=numargs) arg2 = numargs-1; if (arg1>arg2) { while (in[inpos]!='\0' && in[inpos]!='}') inpos++; continue; } off1 = offsets[arg1]; if (arg2+1==numargs) off2 = strlen(text); else off2 = offsets[arg2+1]-1; while (in[inpos]!='\0' && in[inpos]!='}') inpos++; } else if (isdigit((int)in[inpos])) { int arg; if (in[inpos]=='0') arg = 0; else if (in[inpos]=='1') arg = 1; else if (in[inpos]=='2') arg = 2; else if (in[inpos]=='3') arg = 3; else if (in[inpos]=='4') arg = 4; else if (in[inpos]=='5') arg = 5; else if (in[inpos]=='6') arg = 6; else if (in[inpos]=='7') arg = 7; else if (in[inpos]=='8') arg = 8; else arg = 9; if (arg>=numargs) continue; for (off1=off2=offsets[arg]; text[off2]!='\0' && text[off2]!=' ' && text[off2]!='\t'; off2++); } { char * newout; newout = xmalloc(size+(off2-off1)+1); /* curr + new + nul */ size = size+(off2-off1)+1; memmove(newout,out,outpos); xfree(out); out = newout; while (off1<off2) out[outpos++] = text[off1++]; } } out[outpos] = '\0'; return out;}int count_args(char const * text){ int args = 1; char * pointer = (char *)text; int not_ws = 1; for (;*pointer!='\0';pointer++) { if ((not_ws) && (*pointer==' ')) not_ws = 0; if ((not_ws == 0) && (*pointer!=' ')) { not_ws = 1; args++; } } return args; }void get_offsets(char const * text, unsigned int * offsets){ char * pointer = (char *)text; int counter = 1; int not_ws = 1; offsets[0]=0; for (;*pointer!='\0';pointer++) { if ((not_ws) && (*pointer==' ')) not_ws = 0; if ((not_ws == 0) && (*pointer!=' ')) { not_ws = 1; offsets[counter]=(unsigned int)(pointer-text); counter++; } }}static int do_alias(t_connection * c, char const * cmd, char const * text){ t_elem const * elem1; t_elem const * elem2; t_alias const * alias; t_output * output; unsigned int * offsets; int numargs; int match = -1; numargs = count_args(text)-1; offsets=xmalloc(sizeof(unsigned int)*(numargs+1)); get_offsets(text,offsets); LIST_TRAVERSE_CONST(aliaslist_head,elem1) { if (!(alias = elem_get_data(elem1))) continue; if (strstr(alias->alias,cmd)==NULL) continue; LIST_TRAVERSE_CONST(alias->output,elem2) { if (!(output = elem_get_data(elem2))) continue; if (!output->line) continue; if ((output->min==-1) || ((output->min<=numargs) && (output->max==-1)) || ((output->min<=numargs) && (output->max>=numargs))) //TODO: initialize offsets { char * msgtmp; char * tmp2; char * cmd = "%C"; match = 1; if ((msgtmp = replace_args(output->line,offsets,numargs+1,text))) { if (msgtmp[0]!='\0') { if ((msgtmp[0]=='/')&&(msgtmp[1]!='/')) // to make sure we don't get endless aliasing loop { tmp2 = xmalloc(strlen(msgtmp)+3); sprintf(tmp2,"%s%s",cmd,msgtmp); xfree((void *)msgtmp); msgtmp=tmp2; } if (strlen(msgtmp)>MAX_MESSAGE_LEN) { msgtmp[MAX_MESSAGE_LEN]='\0'; eventlog(eventlog_level_info,__FUNCTION__,"message line after alias expansion was too long, truncating it"); } message_send_formatted(c,msgtmp); } xfree((void *)msgtmp); /* avoid warning */ } else eventlog(eventlog_level_error,__FUNCTION__,"could not perform argument replacement"); } } } xfree(offsets); return match;}extern int aliasfile_load(char const * filename){ FILE * afp; char * buff; char * temp; unsigned int line; unsigned int pos; int inalias; t_alias * alias = NULL; if (!filename) { eventlog(eventlog_level_error,__FUNCTION__,"got NULL filename"); return -1; } if (!(afp = fopen(filename,"r"))) { eventlog(eventlog_level_error,__FUNCTION__,"unable to open alias file \"%s\" for reading (fopen: %s)",filename,pstrerror(errno)); return -1; } aliaslist_head = list_create(); inalias = 0; for (line=1; (buff = file_get_line(afp)); line++) { for (pos=0; buff[pos]=='\t' || buff[pos]==' '; pos++); if (buff[pos]=='\0' || buff[pos]=='#') { continue; } if (!(temp = strrchr(buff,'"'))) /* FIXME: assumes comments don't contain " */ temp = buff; if ((temp = strrchr(temp,'#'))) { unsigned int len; unsigned int endpos; *temp = '\0'; len = strlen(buff)+1; for (endpos=len-1; buff[endpos]=='\t' || buff[endpos]==' '; endpos--); buff[endpos+1] = '\0'; } switch (inalias) { case 0: if (buff[pos]!='@') /* not start of alias */ { eventlog(eventlog_level_error,__FUNCTION__,"expected start of alias stanza on line %u of alias file \"%s\" but found \"%s\"",line,filename,&buff[pos]); break; } inalias = 1; break; case 1: { if (buff[pos]=='\0') break; inalias = 2; alias = xmalloc(sizeof(t_alias)); alias->output=0; alias->alias=xstrdup(&buff[pos]); } break; case 2: { char * dummy; char * out = NULL; int min, max; t_output * output; min = max = 0; if (buff[pos]!='[') { eventlog(eventlog_level_error,__FUNCTION__,"expected output entry on line %u of alias file \"%s\" but found \"%s\"",line,filename,&buff[pos]); break; } if ((dummy=strchr(&buff[pos],']'))) { if (dummy[1]!='\0') out = xstrdup(&dummy[1]); } if (buff[pos+1]=='*') { min = max = -1; } else if (buff[pos+1]=='+') { min = 1; max = -1; } else if (sscanf(&buff[pos],"[%u",&min)==1) { if (*(dummy-1)=='+') max = -1; else max = min; } else { eventlog(eventlog_level_error,__FUNCTION__,"error parsing min/max value for alias output"); } if (out!=NULL) { output = xmalloc(sizeof(t_output)); output->min=min; output->max=max; output->line = out; alias->output = list_create(); list_append_data(alias->output,output); inalias = 3; } } break; case 3: { if (buff[pos]=='@') { inalias = 1; if (alias!=NULL) list_append_data(aliaslist_head,alias); alias=NULL; break; } else if (buff[pos]=='[') { char * dummy; char * out = NULL; int min, max; t_output * output; min = max = 0; if ((dummy=strchr(&buff[pos],']'))) { if (dummy[1]!='\0') out = xstrdup(&dummy[1]); } if (buff[pos+1]=='*') { min = max = -1; } else if (buff[pos+1]=='+') { min = 1; max = -1; } else if (sscanf(&buff[pos],"[%u",&min)==1) { if (*(dummy-1)=='+') max = -1; else max = min; } else { eventlog(eventlog_level_error,__FUNCTION__,"error parsing min/max value for alias output"); } if (out!=NULL) { output = xmalloc(sizeof(t_output)); output->min=min; output->max=max; output->line = out; list_append_data(alias->output,output); } } else eventlog(eventlog_level_error,__FUNCTION__,"expected output entry or next alias stanza on line %u of file \"%s\"i but found \"%s\"",line,filename,&buff[pos]); break; } } } if (alias!=NULL) list_append_data(aliaslist_head,alias); file_get_line(NULL); // clear file_get_line buffer fclose(afp); eventlog(eventlog_level_info,__FUNCTION__,"done loading aliases"); return 0;}extern int aliasfile_unload(void){ t_elem * elem1; t_elem * elem2; t_alias const * alias; t_output * output; if (aliaslist_head) { LIST_TRAVERSE(aliaslist_head,elem1) { if (!(alias = elem_get_data(elem1))) /* should not happen */ { eventlog(eventlog_level_error,__FUNCTION__,"alias list contains NULL item"); continue; } if (list_remove_elem(aliaslist_head,&elem1)<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not remove alias"); continue; } if (alias->output) { LIST_TRAVERSE(alias->output,elem2) { if (!(output = elem_get_data(elem2))) { eventlog(eventlog_level_error,__FUNCTION__,"output list contains NULL item"); continue; } if (list_remove_elem(alias->output,&elem2)<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not remove output"); continue; } xfree((void *)output->line); /* avoid warning */ xfree((void *)output); } list_destroy(alias->output); } if (alias->alias) xfree((void *)alias->alias); xfree((void *)alias); } if (list_destroy(aliaslist_head)<0) return -1; aliaslist_head = NULL; } return 0;}extern int handle_alias_command(t_connection * c, char const * text){ unsigned int i,j; char cmd[MAX_COMMAND_LEN]; for (i=j=0; text[i]!=' ' && text[i]!='\0'; i++) /* get command */ if (j<sizeof(cmd)-1) cmd[j++] = text[i]; cmd[j] = '\0'; if (cmd[2]=='\0') return list_aliases(c); if (do_alias(c,cmd,text)<0) { message_send_text(c,message_type_info,c,"No such alias. Use // to show the list."); return -1; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -