/* * commands.c -- user commands handling * * Copyright (C) 2005-2014 Mikael Berthe <mikael@lilotux.net> * * 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, see <http://www.gnu.org/licenses/>. */#include<string.h>#include<stdlib.h>#include<sys/types.h>#include<sys/stat.h>#include<unistd.h>#include<errno.h>#include<glob.h>#include"config.h"#include"commands.h"#include"help.h"#include"roster.h"#include"screen.h"#include"compl.h"#include"hooks.h"#include"hbuf.h"#include"utils.h"#include"settings.h"#include"events.h"#include"otr.h"#include"carbons.h"#include"utf8.h"#include"xmpp.h"#include"main.h"#define IMSTATUS_AWAY "away"#define IMSTATUS_ONLINE "online"#define IMSTATUS_OFFLINE "offline"#define IMSTATUS_FREE4CHAT "free"#define IMSTATUS_AVAILABLE "avail"#define IMSTATUS_NOTAVAILABLE "notavail"#define IMSTATUS_DONOTDISTURB "dnd"#ifdef WITH_DEPRECATED_STATUS_INVISIBLE# define IMSTATUS_INVISIBLE "invisible"#endif// Commands callbacksstaticvoiddo_roster(char*arg);staticvoiddo_status(char*arg);staticvoiddo_status_to(char*arg);staticvoiddo_add(char*arg);staticvoiddo_del(char*arg);staticvoiddo_group(char*arg);staticvoiddo_say(char*arg);staticvoiddo_msay(char*arg);staticvoiddo_say_to(char*arg);staticvoiddo_buffer(char*arg);staticvoiddo_clear(char*arg);staticvoiddo_info(char*arg);staticvoiddo_rename(char*arg);staticvoiddo_move(char*arg);staticvoiddo_set(char*arg);staticvoiddo_alias(char*arg);staticvoiddo_bind(char*arg);staticvoiddo_connect(char*arg);staticvoiddo_disconnect(char*arg);staticvoiddo_quit(char*arg);staticvoiddo_rawxml(char*arg);staticvoiddo_room(char*arg);staticvoiddo_authorization(char*arg);staticvoiddo_version(char*arg);staticvoiddo_request(char*arg);staticvoiddo_event(char*arg);staticvoiddo_help(char*arg);staticvoiddo_pgp(char*arg);staticvoiddo_iline(char*arg);staticvoiddo_screen_refresh(char*arg);staticvoiddo_chat_disable(char*arg);staticvoiddo_source(char*arg);staticvoiddo_color(char*arg);staticvoiddo_otr(char*arg);staticvoiddo_otrpolicy(char*arg);staticvoiddo_echo(char*arg);staticvoiddo_module(char*arg);staticvoiddo_carbons(char*arg);staticvoidroom_bookmark(gpointerbud,char*arg);// Global variable for the commands liststaticGSList*Commands;staticGSList*safe_commands;#ifdef MODULES_ENABLE#include"modules.h"gpointercmd_del(gpointerid){GSList*sl_cmd;if(!id)returnNULL;for(sl_cmd=Commands;sl_cmd;sl_cmd=sl_cmd->next)if(sl_cmd->data==id){cmd*command=(cmd*)sl_cmd->data;gpointeruserdata=command->userdata;Commands=g_slist_delete_link(Commands,sl_cmd);compl_del_category_word(COMPL_CMD,command->name);g_free(command);returnuserdata;}returnNULL;}#endif// cmd_add()// Adds a command to the commands list and to the CMD completion listgpointercmd_add(constchar*name,constchar*help,guintflags_row1,guintflags_row2,void(*f)(char*),gpointeruserdata){cmd*n_cmd=g_new0(cmd,1);strncpy(n_cmd->name,name,32-1);n_cmd->help=help;n_cmd->completion_flags[0]=flags_row1;n_cmd->completion_flags[1]=flags_row2;n_cmd->func=f;n_cmd->userdata=userdata;Commands=g_slist_prepend(Commands,n_cmd);// Add to completion CMD categorycompl_add_category_word(COMPL_CMD,name);returnn_cmd;}// cmd_set_safe(name, safe)// Sets if command can be used in startup configuration file.gbooleancmd_set_safe(constgchar*name,gbooleansafe){GSList*sel;if(!name)returnFALSE;for(sel=safe_commands;sel;sel=sel->next)if(!strcmp((constchar*)sel->data,name)){if(safe){returnFALSE;}else{g_free(sel->data);safe_commands=g_slist_delete_link(safe_commands,sel);}}if(safe)safe_commands=g_slist_append(safe_commands,g_strdup(name));elsereturnFALSE;returnTRUE;}// cmd_is_safe(name)// Returns if command is safe or notgbooleancmd_is_safe(constgchar*name){GSList*sel;if(!name)returnFALSE;for(sel=safe_commands;sel;sel=sel->next)if(!strcmp((constchar*)sel->data,name))returnTRUE;returnFALSE;}// cmd_init()// Commands table initialization// !!!// After changing commands names and it arguments names here, you must change// ones in init_bindings()!//voidcmd_init(void){cmd_add("add","Add a jabber user",COMPL_JID,0,&do_add,NULL);cmd_add("alias","Add an alias",0,0,&do_alias,NULL);cmd_add("authorization","Manage subscription authorizations",COMPL_AUTH,COMPL_JID,&do_authorization,NULL);cmd_add("bind","Add an key binding",0,0,&do_bind,NULL);cmd_add("buffer","Manipulate current buddy's buffer (chat window)",COMPL_BUFFER,0,&do_buffer,NULL);cmd_add("carbons","Manage carbons settings",COMPL_CARBONS,0,&do_carbons,NULL);cmd_add("chat_disable","Disable chat mode",0,0,&do_chat_disable,NULL);cmd_add("clear","Clear the dialog window",0,0,&do_clear,NULL);cmd_add("color","Set coloring options",COMPL_COLOR,0,&do_color,NULL);cmd_add("connect","Connect to the server",0,0,&do_connect,NULL);cmd_add("del","Delete the current buddy",0,0,&do_del,NULL);cmd_add("disconnect","Disconnect from server",0,0,&do_disconnect,NULL);cmd_add("echo","Display a string in the log window",0,0,&do_echo,NULL);cmd_add("event","Process an event",COMPL_EVENTSID,COMPL_EVENTS,&do_event,NULL);cmd_add("group","Change group display settings",COMPL_GROUP,COMPL_GROUPNAME,&do_group,NULL);cmd_add("help","Display some help",COMPL_CMD,0,&do_help,NULL);cmd_add("iline","Manipulate input buffer",0,0,&do_iline,NULL);cmd_add("info","Show basic info on current buddy",0,0,&do_info,NULL);cmd_add("module","Manipulations with modules",COMPL_MODULE,0,&do_module,NULL);cmd_add("move","Move the current buddy to another group",COMPL_GROUPNAME,0,&do_move,NULL);cmd_add("msay","Send a multi-lines message to the selected buddy",COMPL_MULTILINE,0,&do_msay,NULL);cmd_add("otr","Manage OTR settings",COMPL_OTR,COMPL_JID,&do_otr,NULL);cmd_add("otrpolicy","Manage OTR policies",COMPL_JID,COMPL_OTRPOLICY,&do_otrpolicy,NULL);cmd_add("pgp","Manage PGP settings",COMPL_PGP,COMPL_JID,&do_pgp,NULL);cmd_add("quit","Exit the software",0,0,&do_quit,NULL);cmd_add("rawxml","Send a raw XML string",0,0,&do_rawxml,NULL);cmd_add("rename","Rename the current buddy",0,0,&do_rename,NULL);cmd_add("request","Send a Jabber IQ request",COMPL_REQUEST,COMPL_JID,&do_request,NULL);cmd_add("room","MUC actions command",COMPL_ROOM,0,&do_room,NULL);cmd_add("roster","Manipulate the roster/buddylist",COMPL_ROSTER,0,&do_roster,NULL);cmd_add("say","Say something to the selected buddy",0,0,&do_say,NULL);cmd_add("say_to","Say something to a specific buddy",COMPL_JID,0,&do_say_to,NULL);cmd_add("screen_refresh","Redraw mcabber screen",0,0,&do_screen_refresh,NULL);cmd_add("set","Set/query an option value",0,0,&do_set,NULL);cmd_add("source","Read a configuration file",0,0,&do_source,NULL);cmd_add("status","Show or set your status",COMPL_STATUS,0,&do_status,NULL);cmd_add("status_to","Show or set your status for one recipient",COMPL_JID,COMPL_STATUS,&do_status_to,NULL);cmd_add("version","Show mcabber version",0,0,&do_version,NULL);cmd_set_safe("set",TRUE);cmd_set_safe("bind",TRUE);cmd_set_safe("alias",TRUE);cmd_set_safe("pgp",TRUE);cmd_set_safe("source",TRUE);cmd_set_safe("status",TRUE);cmd_set_safe("color",TRUE);cmd_set_safe("otrpolicy",TRUE);cmd_set_safe("module",TRUE);// Status categorycompl_add_category_word(COMPL_STATUS,"online");compl_add_category_word(COMPL_STATUS,"avail");#ifdef WITH_DEPRECATED_STATUS_INVISIBLEcompl_add_category_word(COMPL_STATUS,"invisible");#endifcompl_add_category_word(COMPL_STATUS,"free");compl_add_category_word(COMPL_STATUS,"dnd");compl_add_category_word(COMPL_STATUS,"notavail");compl_add_category_word(COMPL_STATUS,"away");compl_add_category_word(COMPL_STATUS,"offline");compl_add_category_word(COMPL_STATUS,"message");// Roster categorycompl_add_category_word(COMPL_ROSTER,"bottom");compl_add_category_word(COMPL_ROSTER,"top");compl_add_category_word(COMPL_ROSTER,"up");compl_add_category_word(COMPL_ROSTER,"down");compl_add_category_word(COMPL_ROSTER,"group_prev");compl_add_category_word(COMPL_ROSTER,"group_next");compl_add_category_word(COMPL_ROSTER,"hide");compl_add_category_word(COMPL_ROSTER,"show");compl_add_category_word(COMPL_ROSTER,"toggle");compl_add_category_word(COMPL_ROSTER,"display");compl_add_category_word(COMPL_ROSTER,"hide_offline");compl_add_category_word(COMPL_ROSTER,"show_offline");compl_add_category_word(COMPL_ROSTER,"toggle_offline");compl_add_category_word(COMPL_ROSTER,"item_lock");compl_add_category_word(COMPL_ROSTER,"item_unlock");compl_add_category_word(COMPL_ROSTER,"item_toggle_lock");compl_add_category_word(COMPL_ROSTER,"alternate");compl_add_category_word(COMPL_ROSTER,"search");compl_add_category_word(COMPL_ROSTER,"unread_first");compl_add_category_word(COMPL_ROSTER,"unread_next");compl_add_category_word(COMPL_ROSTER,"note");compl_add_category_word(COMPL_ROSTER,"resource_lock");compl_add_category_word(COMPL_ROSTER,"resource_unlock");// Buffer categorycompl_add_category_word(COMPL_BUFFER,"clear");compl_add_category_word(COMPL_BUFFER,"bottom");compl_add_category_word(COMPL_BUFFER,"top");compl_add_category_word(COMPL_BUFFER,"up");compl_add_category_word(COMPL_BUFFER,"down");compl_add_category_word(COMPL_BUFFER,"search_backward");compl_add_category_word(COMPL_BUFFER,"search_forward");compl_add_category_word(COMPL_BUFFER,"readmark");compl_add_category_word(COMPL_BUFFER,"date");compl_add_category_word(COMPL_BUFFER,"%");compl_add_category_word(COMPL_BUFFER,"purge");compl_add_category_word(COMPL_BUFFER,"close");compl_add_category_word(COMPL_BUFFER,"close_all");compl_add_category_word(COMPL_BUFFER,"scroll_lock");compl_add_category_word(COMPL_BUFFER,"scroll_unlock");compl_add_category_word(COMPL_BUFFER,"scroll_toggle");compl_add_category_word(COMPL_BUFFER,"list");compl_add_category_word(COMPL_BUFFER,"save");// Group categorycompl_add_category_word(COMPL_GROUP,"fold");compl_add_category_word(COMPL_GROUP,"unfold");compl_add_category_word(COMPL_GROUP,"toggle");// Multi-line (msay) categorycompl_add_category_word(COMPL_MULTILINE,"abort");compl_add_category_word(COMPL_MULTILINE,"begin");compl_add_category_word(COMPL_MULTILINE,"send");compl_add_category_word(COMPL_MULTILINE,"send_to");compl_add_category_word(COMPL_MULTILINE,"toggle");compl_add_category_word(COMPL_MULTILINE,"toggle_verbatim");compl_add_category_word(COMPL_MULTILINE,"verbatim");// Room categorycompl_add_category_word(COMPL_ROOM,"affil");compl_add_category_word(COMPL_ROOM,"ban");compl_add_category_word(COMPL_ROOM,"bookmark");compl_add_category_word(COMPL_ROOM,"destroy");compl_add_category_word(COMPL_ROOM,"invite");compl_add_category_word(COMPL_ROOM,"join");compl_add_category_word(COMPL_ROOM,"kick");compl_add_category_word(COMPL_ROOM,"leave");compl_add_category_word(COMPL_ROOM,"names");compl_add_category_word(COMPL_ROOM,"nick");compl_add_category_word(COMPL_ROOM,"privmsg");compl_add_category_word(COMPL_ROOM,"remove");compl_add_category_word(COMPL_ROOM,"role");compl_add_category_word(COMPL_ROOM,"setopt");compl_add_category_word(COMPL_ROOM,"topic");compl_add_category_word(COMPL_ROOM,"unban");compl_add_category_word(COMPL_ROOM,"unlock");compl_add_category_word(COMPL_ROOM,"whois");// Authorization categorycompl_add_category_word(COMPL_AUTH,"allow");compl_add_category_word(COMPL_AUTH,"cancel");compl_add_category_word(COMPL_AUTH,"request");compl_add_category_word(COMPL_AUTH,"request_unsubscribe");// Request (query) categorycompl_add_category_word(COMPL_REQUEST,"last");compl_add_category_word(COMPL_REQUEST,"ping");compl_add_category_word(COMPL_REQUEST,"time");compl_add_category_word(COMPL_REQUEST,"vcard");compl_add_category_word(COMPL_REQUEST,"version");// Events categorycompl_add_category_word(COMPL_EVENTS,"accept");compl_add_category_word(COMPL_EVENTS,"ignore");compl_add_category_word(COMPL_EVENTS,"reject");// PGP categorycompl_add_category_word(COMPL_PGP,"disable");compl_add_category_word(COMPL_PGP,"enable");compl_add_category_word(COMPL_PGP,"force");compl_add_category_word(COMPL_PGP,"info");compl_add_category_word(COMPL_PGP,"setkey");// OTR categorycompl_add_category_word(COMPL_OTR,"start");compl_add_category_word(COMPL_OTR,"stop");compl_add_category_word(COMPL_OTR,"fingerprint");compl_add_category_word(COMPL_OTR,"smpq");compl_add_category_word(COMPL_OTR,"smpr");compl_add_category_word(COMPL_OTR,"smpa");compl_add_category_word(COMPL_OTR,"info");compl_add_category_word(COMPL_OTR,"key");// OTR Policy categorycompl_add_category_word(COMPL_OTRPOLICY,"plain");compl_add_category_word(COMPL_OTRPOLICY,"manual");compl_add_category_word(COMPL_OTRPOLICY,"opportunistic");compl_add_category_word(COMPL_OTRPOLICY,"always");// Color categorycompl_add_category_word(COMPL_COLOR,"roster");compl_add_category_word(COMPL_COLOR,"muc");compl_add_category_word(COMPL_COLOR,"mucnick");#ifdef MODULES_ENABLE// Module categorycompl_add_category_word(COMPL_MODULE,"info");compl_add_category_word(COMPL_MODULE,"list");compl_add_category_word(COMPL_MODULE,"load");compl_add_category_word(COMPL_MODULE,"unload");#endif// Carbons categorycompl_add_category_word(COMPL_CARBONS,"info");compl_add_category_word(COMPL_CARBONS,"enable");compl_add_category_word(COMPL_CARBONS,"disable");}// expandalias(line)// If there is one, expand the alias in line and returns a new allocated line// If no alias is found, returns line// Note: if the returned pointer is different from line, the caller should// g_free() the pointer after usechar*expandalias(constchar*line){constchar*p1,*p2;char*word;constgchar*value;char*newline=(char*)line;// Ignore leading COMMAND_CHARfor(p1=line;*p1==COMMAND_CHAR;p1++);// Locate the end of the wordfor(p2=p1;*p2&&(*p2!=' ');p2++);// Extract the word and look for an alias in the listword=g_strndup(p1,p2-p1);value=settings_get(SETTINGS_TYPE_ALIAS,(constchar*)word);g_free(word);if(value)newline=g_strdup_printf("%c%s%s",COMMAND_CHAR,value,p2);returnnewline;}// cmd_get// Finds command in the command list structure.// Returns a pointer to the cmd entry, or NULL if command not found.cmd*cmd_get(constchar*command){constchar*p1,*p2;char*com;GSList*sl_com;// Ignore leading COMMAND_CHARfor(p1=command;*p1==COMMAND_CHAR;p1++);// Locate the end of the commandfor(p2=p1;*p2&&(*p2!=' ');p2++);// Copy the clean commandcom=g_strndup(p1,p2-p1);// Look for command in the listfor(sl_com=Commands;sl_com;sl_com=g_slist_next(sl_com)){if(!strcasecmp(com,((cmd*)sl_com->data)->name))break;}g_free(com);if(sl_com)// Command has been found.return(cmd*)sl_com->data;returnNULL;}// process_command(line, iscmd)// Process a command line.// If iscmd is TRUE, process the command even if verbatim mmode is set;// it is intended to be used for key bindings.voidprocess_command(constchar*line,guintiscmd){char*p;char*xpline;cmd*curcmd;if(!line)return;// We do alias expansion hereif(iscmd||scr_get_multimode()!=2)xpline=expandalias(line);elsexpline=(char*)line;// No expansion in verbatim multi-line mode// We want to use a copyif(xpline==line)xpline=g_strdup(line);// Remove trailing spaces:for(p=xpline;*p;p++);for(p--;p>xpline&&(*p==' ');p--)*p=0;// If verbatim multi-line mode, we check if another /msay command is typedif(!iscmd&&scr_get_multimode()==2&&(strncasecmp(xpline,mkcmdstr("msay "),strlen(mkcmdstr("msay "))))){// It isn't an /msay commandscr_append_multiline(xpline);g_free(xpline);return;}// Commands handlingcurcmd=cmd_get(xpline);if(!curcmd){scr_LogPrint(LPRINT_NORMAL,"Unrecognized command. ""Please see the manual for a list of known commands.");g_free(xpline);return;}if(!curcmd->func){scr_LogPrint(LPRINT_NORMAL,"This functionality is not yet implemented, sorry.");g_free(xpline);return;}// Lets go to the command parametersfor(p=xpline+1;*p&&(*p!=' ');p++);// Skip spaceswhile(*p&&(*p==' '))p++;// Call command-specific function#ifdef MODULES_ENABLEif(curcmd->userdata)(*(void(*)(char*p,gpointeru))curcmd->func)(p,curcmd->userdata);else(*curcmd->func)(p);#else(*curcmd->func)(p);#endifg_free(xpline);}// process_line(line)// Process a command/message line.// If this isn't a command, this is a message and it is sent to the// currently selected buddy.voidprocess_line(constchar*line){if(!*line){// User only pressed enterif(scr_get_multimode()){scr_append_multiline("");return;}if(current_buddy){if(buddy_gettype(BUDDATA(current_buddy))&ROSTER_TYPE_GROUP){do_group("toggle");}else{// Enter chat modescr_set_chatmode(TRUE);scr_show_buddy_window();}}return;}if(*line!=COMMAND_CHAR){// This isn't a commandif(scr_get_multimode())scr_append_multiline(line);elsesay_cmd((char*)line,0);return;}/* It is _probably_ a command -- except for verbatim multi-line mode */process_command(line,FALSE);}// Helper routine for buffer item_{lock,unlock,toggle_lock}// "lock" values: 1=lock 0=unlock -1=invertstaticvoidroster_buddylock(char*bjid,intlock){gpointerbud=NULL;boolmay_need_refresh=FALSE;// Allow special jid "" or "." (current buddy)if(bjid&&(!*bjid||!strcmp(bjid,".")))bjid=NULL;if(bjid){// The JID has been specified. Quick check...if(check_jid_syntax(bjid)){scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"<%s> is not a valid Jabber ID.",bjid);}else{// Find the buddyGSList*roster_elt;roster_elt=roster_find(bjid,jidsearch,ROSTER_TYPE_USER|ROSTER_TYPE_ROOM);if(roster_elt)bud=roster_elt->data;elsescr_LogPrint(LPRINT_NORMAL,"This jid isn't in the roster.");may_need_refresh=TRUE;}}else{// Use the current buddyif(current_buddy)bud=BUDDATA(current_buddy);}// Update the ROSTER_FLAG_USRLOCK flagif(bud){if(lock==-1)lock=!(buddy_getflags(bud)&ROSTER_FLAG_USRLOCK);buddy_setflags(bud,ROSTER_FLAG_USRLOCK,lock);if(may_need_refresh){buddylist_build();update_roster=TRUE;}}}staticvoidroster_resourcelock(char*jidres,gbooleanlock){gpointerbud=NULL;char*resource=NULL;if(!jidres){if(lock)return;jidres=".";}if(jidres[0]=='.'&&(jidres[1]=='\0'||jidres[1]==JID_RESOURCE_SEPARATOR)){//Special jid: . or ./resourceswitch(jidres[1]){caseJID_RESOURCE_SEPARATOR:resource=jidres+2;case'\0':if(current_buddy)bud=BUDDATA(current_buddy);}}else{char*tmp;if(!check_jid_syntax(jidres)&&(tmp=strchr(jidres,JID_RESOURCE_SEPARATOR))){//Any other valid full jid*tmp='\0';// for roster search by bare jid;resource=tmp+1;GSList*roster_elt;roster_elt=roster_find(jidres,jidsearch,ROSTER_TYPE_USER|ROSTER_TYPE_AGENT);if(roster_elt)bud=roster_elt->data;*tmp=JID_RESOURCE_SEPARATOR;}if(!bud){//Resource for current buddyif(current_buddy)bud=BUDDATA(current_buddy);resource=jidres;}}if(bud&&buddy_gettype(bud)&(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT)){if(lock){GSList*resources,*p_res;gbooleanfound=FALSE;resources=buddy_getresources(bud);for(p_res=resources;p_res;p_res=g_slist_next(p_res)){if(!g_strcmp0((char*)p_res->data,resource))found=TRUE;g_free(p_res->data);}g_slist_free(resources);if(!found){scr_LogPrint(LPRINT_NORMAL,"No such resource <%s>...",jidres);return;}}else{resource=NULL;}buddy_setactiveresource(bud,resource);scr_update_chat_status(TRUE);}}// display_and_free_note(note, winId)// Display the note information in the winId buffer, and free note// (winId is a bare jid or NULL for the status window, in which case we// display the note jid too)staticvoiddisplay_and_free_note(structannotation*note,constchar*winId){gchartbuf[128];GString*sbuf;guintmsg_flag=HBB_PREFIX_INFO;/* We use the flag prefix_info for the first line, and prefix_cont for the other lines, for better readability */if(!note)return;sbuf=g_string_new("");if(!winId){// We're writing to the status window, so let's show the jid too.g_string_printf(sbuf,"Annotation on <%s>",note->jid);scr_WriteIncomingMessage(winId,sbuf->str,0,msg_flag,0);msg_flag=HBB_PREFIX_INFO|HBB_PREFIX_CONT;}// If we have the creation date, display itif(note->cdate){strftime(tbuf,sizeof(tbuf),"%Y-%m-%d %H:%M:%S",localtime(&note->cdate));g_string_printf(sbuf,"Note created %s",tbuf);scr_WriteIncomingMessage(winId,sbuf->str,0,msg_flag,0);msg_flag=HBB_PREFIX_INFO|HBB_PREFIX_CONT;}// If we have the modification date, display it// unless it's the same as the creation dateif(note->mdate&&note->mdate!=note->cdate){strftime(tbuf,sizeof(tbuf),"%Y-%m-%d %H:%M:%S",localtime(&note->mdate));g_string_printf(sbuf,"Note modified %s",tbuf);scr_WriteIncomingMessage(winId,sbuf->str,0,msg_flag,0);msg_flag=HBB_PREFIX_INFO|HBB_PREFIX_CONT;}// Note textg_string_printf(sbuf,"Note: %s",note->text);scr_WriteIncomingMessage(winId,sbuf->str,0,msg_flag,0);g_string_free(sbuf,TRUE);g_free(note->text);g_free(note->jid);g_free(note);}staticvoiddisplay_all_annotations(void){GSList*notes;notes=xmpp_get_all_storage_rosternotes();if(!notes)return;// Call display_and_free_note() for each note,// with winId = NULL (special window)g_slist_foreach(notes,(GFunc)&display_and_free_note,NULL);scr_setmsgflag_if_needed(SPECIAL_BUFFER_STATUS_ID,TRUE);scr_setattentionflag_if_needed(SPECIAL_BUFFER_STATUS_ID,TRUE,ROSTER_UI_PRIO_STATUS_WIN_MESSAGE,prio_max);g_slist_free(notes);}staticvoidroster_note(char*arg){constchar*bjid;guinttype;if(!current_buddy)return;bjid=buddy_getjid(BUDDATA(current_buddy));type=buddy_gettype(BUDDATA(current_buddy));if(!bjid&&type==ROSTER_TYPE_SPECIAL&&!arg){// We're in the status window (the only special buffer currently)// Let's display all server notesdisplay_all_annotations();return;}if(!bjid||(type!=ROSTER_TYPE_USER&&type!=ROSTER_TYPE_ROOM&&type!=ROSTER_TYPE_AGENT)){scr_LogPrint(LPRINT_NORMAL,"This item can't have a note.");return;}if(arg&&*arg){// Set a notegchar*msg,*notetxt;msg=to_utf8(arg);if(!strcmp(msg,"-"))notetxt=NULL;// delete noteelsenotetxt=msg;xmpp_set_storage_rosternotes(bjid,notetxt);g_free(msg);}else{// Display a notestructannotation*note=xmpp_get_storage_rosternotes(bjid,FALSE);if(note){display_and_free_note(note,bjid);}else{scr_WriteIncomingMessage(bjid,"This item doesn't have a note.",0,HBB_PREFIX_INFO,0);}}}// roster_updown(updown, nitems)// updown: -1=up, +1=downinlinestaticvoidroster_updown(intupdown,char*nitems){intnbitems;if(!nitems||!*nitems)nbitems=1;elsenbitems=strtol(nitems,NULL,10);if(nbitems>0)scr_roster_up_down(updown,nbitems);}/* Commands callback functions *//* All these do_*() functions will be called with a "arg" parameter *//* (with arg not null) */staticvoiddo_roster(char*arg){char**paramlst;char*subcmd;paramlst=split_arg(arg,2,1);// subcmd, argsubcmd=*paramlst;arg=*(paramlst+1);if(!subcmd||!*subcmd){scr_LogPrint(LPRINT_NORMAL,"Missing parameter.");free_arg_lst(paramlst);return;}if(!strcasecmp(subcmd,"top")){scr_roster_top();update_roster=TRUE;}elseif(!strcasecmp(subcmd,"bottom")){scr_roster_bottom();update_roster=TRUE;}elseif(!strcasecmp(subcmd,"hide")){scr_roster_visibility(0);}elseif(!strcasecmp(subcmd,"show")){scr_roster_visibility(1);}elseif(!strcasecmp(subcmd,"toggle")){scr_roster_visibility(-1);}elseif(!strcasecmp(subcmd,"hide_offline")){buddylist_set_hide_offline_buddies(TRUE);if(current_buddy)buddylist_build();update_roster=TRUE;}elseif(!strcasecmp(subcmd,"show_offline")){buddylist_set_hide_offline_buddies(FALSE);buddylist_build();update_roster=TRUE;}elseif(!strcasecmp(subcmd,"toggle_offline")){buddylist_set_hide_offline_buddies(-1);buddylist_build();update_roster=TRUE;}elseif(!strcasecmp(subcmd,"display")){scr_roster_display(arg);}elseif(!strcasecmp(subcmd,"item_lock")){roster_buddylock(arg,1);}elseif(!strcasecmp(subcmd,"item_unlock")){roster_buddylock(arg,0);}elseif(!strcasecmp(subcmd,"item_toggle_lock")){roster_buddylock(arg,-1);}elseif(!strcasecmp(subcmd,"unread_first")){scr_roster_unread_message(0);}elseif(!strcasecmp(subcmd,"unread_next")){scr_roster_unread_message(1);}elseif(!strcasecmp(subcmd,"next_open_buffer")){scr_roster_next_open_buffer();}elseif(!strcasecmp(subcmd,"alternate")){scr_roster_jump_alternate();}elseif(!strncasecmp(subcmd,"search",6)){strip_arg_special_chars(arg);if(!arg||!*arg){scr_LogPrint(LPRINT_NORMAL,"What name or JID are you looking for?");free_arg_lst(paramlst);return;}scr_roster_search(arg);update_roster=TRUE;}elseif(!strcasecmp(subcmd,"up")){roster_updown(-1,arg);}elseif(!strcasecmp(subcmd,"down")){roster_updown(1,arg);}elseif(!strcasecmp(subcmd,"group_prev")){scr_roster_prev_group();}elseif(!strcasecmp(subcmd,"group_next")){scr_roster_next_group();}elseif(!strcasecmp(subcmd,"note")){roster_note(arg);}elseif(!strcasecmp(subcmd,"resource_lock")){roster_resourcelock(arg,TRUE);}elseif(!strcasecmp(subcmd,"resource_unlock")){roster_resourcelock(arg,FALSE);}else{scr_LogPrint(LPRINT_NORMAL,"Unrecognized parameter!");}free_arg_lst(paramlst);}voiddo_color(char*arg){char**paramlst;char*subcmd;paramlst=split_arg(arg,2,1);// subcmd, argsubcmd=*paramlst;arg=*(paramlst+1);if(!subcmd||!*subcmd){scr_LogPrint(LPRINT_NORMAL,"Missing parameter.");free_arg_lst(paramlst);return;}if(!strcasecmp(subcmd,"roster")){char*status,*wildcard,*color;char**arglist=split_arg(arg,3,0);status=*arglist;wildcard=to_utf8(arglist[1]);color=arglist[2];if(status&&!strcmp(status,"clear")){// Not a color command, clear allscr_roster_clear_color();update_roster=TRUE;}else{if(!status||!*status||!wildcard||!*wildcard||!color||!*color){scr_LogPrint(LPRINT_NORMAL,"Missing argument");}else{update_roster=scr_roster_color(status,wildcard,color)||update_roster;}}free_arg_lst(arglist);g_free(wildcard);}elseif(!strcasecmp(subcmd,"muc")){char**arglist=split_arg(arg,2,0);char*free_muc=to_utf8(*arglist);constchar*muc=free_muc,*mode=arglist[1];if(!muc||!*muc){scr_LogPrint(LPRINT_NORMAL,"What MUC?");}else{if(!strcmp(muc,"."))if(!(muc=CURRENT_JID))scr_LogPrint(LPRINT_NORMAL,"No JID selected");if(muc){if(check_jid_syntax(muc)&&strcmp(muc,"*")){scr_LogPrint(LPRINT_NORMAL,"Not a JID");}else{if(!mode||!*mode||!strcasecmp(mode,"on"))scr_muc_color(muc,MC_ALL);elseif(!strcasecmp(mode,"preset"))scr_muc_color(muc,MC_PRESET);elseif(!strcasecmp(mode,"off"))scr_muc_color(muc,MC_OFF);elseif(!strcmp(mode,"-"))scr_muc_color(muc,MC_REMOVE);elsescr_LogPrint(LPRINT_NORMAL,"Unknown coloring mode");}}}free_arg_lst(arglist);g_free(free_muc);}elseif(!strcasecmp(subcmd,"mucnick")){char**arglist=split_arg(arg,2,0);constchar*nick=*arglist,*color=arglist[1];if(!nick||!*nick||!color||!*color)scr_LogPrint(LPRINT_NORMAL,"Missing argument");elsescr_muc_nick_color(nick,color);free_arg_lst(arglist);}else{scr_LogPrint(LPRINT_NORMAL,"Unrecognized parameter!");}free_arg_lst(paramlst);}// cmd_setstatus(recipient, arg)// Set your Jabber status.// - if recipient is not NULL, the status is sent to this contact only// - arg must be "status message" (message is optional)voidcmd_setstatus(constchar*recipient,constchar*arg){char**paramlst;char*status;char*msg;enumimstatusst;if(!xmpp_is_online())scr_LogPrint(LPRINT_NORMAL,"You are currently not connected...");// We do not return now, so that the status is memorized and used later...// It makes sense to reset autoaway before changing the status// (esp. for FIFO or remote commands) or the behaviour could be// unexpected...if(!recipient)scr_check_auto_away(TRUE);paramlst=split_arg(arg,2,1);// status, messagestatus=*paramlst;msg=*(paramlst+1);if(!status){free_arg_lst(paramlst);return;}if(!strcasecmp(status,IMSTATUS_OFFLINE))st=offline;elseif(!strcasecmp(status,IMSTATUS_ONLINE))st=available;elseif(!strcasecmp(status,IMSTATUS_AVAILABLE))st=available;elseif(!strcasecmp(status,IMSTATUS_AWAY))st=away;#ifdef WITH_DEPRECATED_STATUS_INVISIBLEelseif(!strcasecmp(status,IMSTATUS_INVISIBLE))st=invisible;#endifelseif(!strcasecmp(status,IMSTATUS_DONOTDISTURB))st=dontdisturb;elseif(!strcasecmp(status,IMSTATUS_NOTAVAILABLE))st=notavail;elseif(!strcasecmp(status,IMSTATUS_FREE4CHAT))st=freeforchat;elseif(!strcasecmp(status,"message")){if(!msg||!*msg){// We want a message. If there's none, we give up.scr_LogPrint(LPRINT_NORMAL,"Missing parameter.");free_arg_lst(paramlst);return;}st=xmpp_getstatus();// Preserve current status}else{scr_LogPrint(LPRINT_NORMAL,"Unrecognized status!");free_arg_lst(paramlst);return;}// Use provided messageif(msg&&!*msg){msg=NULL;}// If a recipient is specified, let's don't use default status messagesif(recipient&&!msg)msg="";xmpp_setstatus(st,recipient,msg,FALSE);free_arg_lst(paramlst);}staticvoiddo_status(char*arg){if(!*arg){constchar*sm=xmpp_getstatusmsg();scr_LogPrint(LPRINT_NORMAL,"Your status is: [%c] %s",imstatus2char[xmpp_getstatus()],(sm?sm:""));return;}arg=to_utf8(arg);cmd_setstatus(NULL,arg);g_free(arg);}staticvoiddo_status_to(char*arg){char**paramlst;char*fjid,*st,*msg;char*jid_utf8=NULL;paramlst=split_arg(arg,3,1);// jid, status, [message]fjid=*paramlst;st=*(paramlst+1);msg=*(paramlst+2);if(!fjid||!st){scr_LogPrint(LPRINT_NORMAL,"Please specify both a Jabber ID and a status.");free_arg_lst(paramlst);return;}// Allow things like /status_to "" awayif(!*fjid||!strcmp(fjid,"."))fjid=NULL;if(fjid){// The JID has been specified. Quick check...if(check_jid_syntax(fjid)){scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"<%s> is not a valid Jabber ID.",fjid);fjid=NULL;}else{// Convert jid to lowercasechar*p=fjid;for(;*p&&*p!=JID_RESOURCE_SEPARATOR;p++)*p=tolower(*p);fjid=jid_utf8=to_utf8(fjid);}}else{// Add the current buddyif(current_buddy)fjid=(char*)buddy_getjid(BUDDATA(current_buddy));if(!fjid)scr_LogPrint(LPRINT_NORMAL,"Please specify a Jabber ID.");}if(fjid){char*cmdline;if(!msg)msg="";msg=to_utf8(msg);cmdline=g_strdup_printf("%s %s",st,msg);scr_LogPrint(LPRINT_LOGNORM,"Sending to <%s> /status %s",fjid,cmdline);cmd_setstatus(fjid,cmdline);g_free(msg);g_free(cmdline);g_free(jid_utf8);}free_arg_lst(paramlst);}staticvoiddo_add(char*arg){char**paramlst;char*id,*nick;char*jid_utf8=NULL;if(!xmpp_is_online()){scr_LogPrint(LPRINT_NORMAL,"You are not connected.");return;}paramlst=split_arg(arg,2,0);// jid, [nickname]id=*paramlst;nick=*(paramlst+1);if(!id)nick=NULL;// Allow things like: /add "" nickelseif(!*id||!strcmp(id,"."))id=NULL;if(id){// The JID has been specified. Quick check...if(check_jid_syntax(id)){scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"<%s> is not a valid Jabber ID.",id);id=NULL;}else{mc_strtolower(id);id=jid_utf8=to_utf8(id);}}else{// Add the current buddyif(current_buddy)id=(char*)buddy_getjid(BUDDATA(current_buddy));if(!id)scr_LogPrint(LPRINT_NORMAL,"Please specify a Jabber ID.");}if(nick)nick=to_utf8(nick);if(id){// 2nd parameter = optional nicknamexmpp_addbuddy(id,nick,NULL);scr_LogPrint(LPRINT_LOGNORM,"Sent presence notification request to <%s>.",id);}g_free(jid_utf8);g_free(nick);free_arg_lst(paramlst);}staticvoiddo_del(char*arg){constchar*bjid;if(*arg){scr_LogPrint(LPRINT_NORMAL,"This action does not require a parameter; ""the currently-selected buddy will be deleted.");return;}if(!current_buddy)return;bjid=buddy_getjid(BUDDATA(current_buddy));if(!bjid)return;if(buddy_gettype(BUDDATA(current_buddy))&ROSTER_TYPE_ROOM){// This is a chatroomif(buddy_getinsideroom(BUDDATA(current_buddy))){scr_LogPrint(LPRINT_NORMAL,"You haven't left this room!");return;}}// Close the bufferscr_buffer_purge(1,NULL);scr_LogPrint(LPRINT_LOGNORM,"Removing <%s>...",bjid);xmpp_delbuddy(bjid);scr_update_buddy_window();}staticvoiddo_group(char*arg){gpointergroup=NULL;guintleave_buddywindow;char**paramlst;char*subcmd;enum{group_toggle=-1,group_unfold=0,group_fold=1}group_state=0;if(!*arg){scr_LogPrint(LPRINT_NORMAL,"Missing parameter.");return;}if(!current_buddy)return;paramlst=split_arg(arg,2,0);// subcmd, [arg]subcmd=*paramlst;arg=*(paramlst+1);if(!subcmd||!*subcmd)gotodo_group_return;// Should not happenif(!strcasecmp(subcmd,"expand")||!strcasecmp(subcmd,"unfold")){group_state=group_unfold;}elseif(!strcasecmp(subcmd,"shrink")||!strcasecmp(subcmd,"fold")){group_state=group_fold;}elseif(!strcasecmp(subcmd,"toggle")){group_state=group_toggle;}else{scr_LogPrint(LPRINT_NORMAL,"Unrecognized parameter!");gotodo_group_return;}if(arg&&*arg){GSList*roster_elt;char*group_utf8=to_utf8(arg);roster_elt=roster_find(group_utf8,namesearch,ROSTER_TYPE_GROUP);g_free(group_utf8);if(roster_elt)group=buddy_getgroup(roster_elt->data);}else{group=buddy_getgroup(BUDDATA(current_buddy));}if(!group){scr_LogPrint(LPRINT_NORMAL,"Group not found.");gotodo_group_return;}// We'll have to redraw the chat window if we're not currently on the group// entry itself, because it means we'll have to leave the current buddy// chat window.leave_buddywindow=(group!=BUDDATA(current_buddy)&&group==buddy_getgroup(BUDDATA(current_buddy)));if(!(buddy_gettype(group)&ROSTER_TYPE_GROUP)){scr_LogPrint(LPRINT_NORMAL,"You need to select a group.");gotodo_group_return;}if(group_state!=group_unfold&&leave_buddywindow)scr_roster_prev_group();buddy_hide_group(group,group_state);buddylist_build();update_roster=TRUE;do_group_return:free_arg_lst(paramlst);}staticintsend_message_to(constchar*fjid,constchar*msg,constchar*subj,LmMessageSubTypetype_overwrite,boolquiet){char*bare_jid,*rp;char*hmsg;gintcrypted;gintretval=0;intisroom;gpointerxep184=NULL;if(!xmpp_is_online()){scr_LogPrint(LPRINT_NORMAL,"You are not connected.");return1;}if(!fjid||!*fjid){scr_LogPrint(LPRINT_NORMAL,"You must specify a Jabber ID.");return1;}if(!msg||!*msg){scr_LogPrint(LPRINT_NORMAL,"You must specify a message.");return1;}if(check_jid_syntax((char*)fjid)){scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"<%s> is not a valid Jabber ID.",fjid);return1;}// We must use the bare jid in hk_message_out()rp=strchr(fjid,JID_RESOURCE_SEPARATOR);if(rp)bare_jid=g_strndup(fjid,rp-fjid);elsebare_jid=(char*)fjid;if(!quiet){// Jump to window, create one if neededscr_roster_jump_jid(bare_jid);}// Check if we're sending a message to a conference room// If not, we must make sure rp is NULL, for hk_message_out()isroom=!!roster_find(bare_jid,jidsearch,ROSTER_TYPE_ROOM);if(rp){if(isroom)rp++;elserp=NULL;}isroom=isroom&&(!rp||!*rp);// local part (UI, logging, etc.)if(subj)hmsg=g_strdup_printf("[%s]\n%s",subj,msg);elsehmsg=(char*)msg;// Network partxmpp_send_msg(fjid,msg,(isroom?ROSTER_TYPE_ROOM:ROSTER_TYPE_USER),subj,FALSE,&crypted,type_overwrite,&xep184);if(crypted==-1){scr_LogPrint(LPRINT_LOGNORM,"Encryption error. Message was not sent.");retval=1;gotosend_message_to_return;}// Hookif(!isroom)hk_message_out(bare_jid,rp,0,hmsg,crypted,FALSE,xep184);send_message_to_return:if(hmsg!=msg)g_free(hmsg);if(rp)g_free(bare_jid);returnretval;}// send_message(msg, subj, type_overwrite)// Write the message in the buddy's window and send the message on// the network.staticvoidsend_message(constchar*msg,constchar*subj,LmMessageSubTypetype_overwrite){constchar*bjid;char*jid;constchar*activeres;if(!current_buddy){scr_LogPrint(LPRINT_NORMAL,"No buddy is currently selected.");return;}bjid=CURRENT_JID;if(!bjid){scr_LogPrint(LPRINT_NORMAL,"No buddy is currently selected.");return;}activeres=buddy_getactiveresource(BUDDATA(current_buddy));if(activeres)jid=g_strdup_printf("%s/%s",bjid,activeres);elsejid=g_strdup(bjid);send_message_to(jid,msg,subj,type_overwrite,FALSE);g_free(jid);}staticLmMessageSubTypescan_mtype(char**arg){// Try splitting itchar**parlist=split_arg(*arg,2,1);LmMessageSubTyperesult=LM_MESSAGE_SUB_TYPE_NOT_SET;// Is it a good parameter?if(parlist&&*parlist){if(!strcmp("-n",*parlist)){result=LM_MESSAGE_SUB_TYPE_NORMAL;}elseif(!strcmp("-h",*parlist)){result=LM_MESSAGE_SUB_TYPE_HEADLINE;}if(result!=LM_MESSAGE_SUB_TYPE_NOT_SET||(!strcmp("--",*parlist)))*arg+=strlen(*arg)-(parlist[1]?strlen(parlist[1]):0);}// Anything found? -> skip itfree_arg_lst(parlist);returnresult;}voidsay_cmd(char*arg,intparse_flags){gpointerbud;LmMessageSubTypemsgtype=LM_MESSAGE_SUB_TYPE_NOT_SET;scr_set_chatmode(TRUE);scr_show_buddy_window();if(!current_buddy){scr_LogPrint(LPRINT_NORMAL,"Whom are you talking to? Please select a buddy.");return;}bud=BUDDATA(current_buddy);if(!(buddy_gettype(bud)&(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_ROOM))){scr_LogPrint(LPRINT_NORMAL,"This is not a user.");return;}buddy_setflags(bud,ROSTER_FLAG_LOCK,TRUE);if(parse_flags)msgtype=scan_mtype(&arg);arg=to_utf8(arg);send_message(arg,NULL,msgtype);g_free(arg);}staticvoiddo_say(char*arg){say_cmd(arg,1);}staticvoiddo_msay(char*arg){/* Parameters: begin verbatim abort send send_to */char**paramlst;char*subcmd;paramlst=split_arg(arg,2,1);// subcmd, argsubcmd=*paramlst;arg=*(paramlst+1);if(!subcmd||!*subcmd){scr_LogPrint(LPRINT_NORMAL,"Missing parameter.");scr_LogPrint(LPRINT_NORMAL,"Please read the manual before using ""the /msay command.");scr_LogPrint(LPRINT_NORMAL,"(Use \"%s begin\" to enter ""multi-line mode...)",mkcmdstr("msay"));gotodo_msay_return;}if(!strcasecmp(subcmd,"toggle")){if(scr_get_multimode())subcmd="send";elsesubcmd="begin";}elseif(!strcasecmp(subcmd,"toggle_verbatim")){if(scr_get_multimode())subcmd="send";elsesubcmd="verbatim";}if(!strcasecmp(subcmd,"abort")){if(scr_get_multimode())scr_LogPrint(LPRINT_NORMAL,"Leaving multi-line message mode.");scr_set_multimode(FALSE,NULL);gotodo_msay_return;}elseif((!strcasecmp(subcmd,"begin"))||(!strcasecmp(subcmd,"verbatim"))){boolverbat;gchar*subj_utf8=to_utf8(arg);if(!strcasecmp(subcmd,"verbatim")){scr_set_multimode(2,subj_utf8);verbat=TRUE;}else{scr_set_multimode(1,subj_utf8);verbat=FALSE;}scr_LogPrint(LPRINT_NORMAL,"Entered %smulti-line message mode.",verbat?"VERBATIM ":"");scr_LogPrint(LPRINT_NORMAL,"Select a buddy and use \"%s send\" ""when your message is ready.",mkcmdstr("msay"));if(verbat)scr_LogPrint(LPRINT_NORMAL,"Use \"%s abort\" to abort this mode.",mkcmdstr("msay"));g_free(subj_utf8);gotodo_msay_return;}elseif(strcasecmp(subcmd,"send")&&strcasecmp(subcmd,"send_to")){scr_LogPrint(LPRINT_NORMAL,"Unrecognized parameter!");gotodo_msay_return;}/* send/send_to command */if(!scr_get_multimode()){scr_LogPrint(LPRINT_NORMAL,"No message to send. ""Use \"%s begin\" first.",mkcmdstr("msay"));gotodo_msay_return;}scr_set_chatmode(TRUE);scr_show_buddy_window();if(!strcasecmp(subcmd,"send_to")){interr=FALSE;gchar*msg_utf8;LmMessageSubTypemsg_type=scan_mtype(&arg);// Let's send to the specified JID. We leave now if there// has been an error (so we don't leave multi-line mode).arg=to_utf8(arg);msg_utf8=to_utf8(scr_get_multiline());if(msg_utf8){err=send_message_to(arg,msg_utf8,scr_get_multimode_subj(),msg_type,FALSE);g_free(msg_utf8);}g_free(arg);if(err)gotodo_msay_return;}else{// Send to currently selected buddygpointerbud;gchar*msg_utf8;if(!current_buddy){scr_LogPrint(LPRINT_NORMAL,"Whom are you talking to?");gotodo_msay_return;}bud=BUDDATA(current_buddy);if(!(buddy_gettype(bud)&(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_ROOM))){scr_LogPrint(LPRINT_NORMAL,"This is not a user.");gotodo_msay_return;}buddy_setflags(bud,ROSTER_FLAG_LOCK,TRUE);msg_utf8=to_utf8(scr_get_multiline());if(msg_utf8){send_message(msg_utf8,scr_get_multimode_subj(),scan_mtype(&arg));g_free(msg_utf8);}}scr_set_multimode(FALSE,NULL);scr_LogPrint(LPRINT_NORMAL,"You have left multi-line message mode.");do_msay_return:free_arg_lst(paramlst);}// load_message_from_file(filename)// Read the whole content of a file.// The data are converted to UTF8, they should be freed by the caller after// use.char*load_message_from_file(constchar*filename){FILE*fd;structstatbuf;char*msgbuf,*msgbuf_utf8;char*p;char*next_utf8_char;size_tlen;fd=fopen(filename,"r");if(!fd||fstat(fileno(fd),&buf)){scr_LogPrint(LPRINT_LOGNORM,"Cannot open message file (%s)",filename);returnNULL;}if(!buf.st_size||buf.st_size>=HBB_BLOCKSIZE){if(!buf.st_size)scr_LogPrint(LPRINT_LOGNORM,"Message file is empty (%s)",filename);elsescr_LogPrint(LPRINT_LOGNORM,"Message file is too big (%s)",filename);fclose(fd);returnNULL;}msgbuf=g_new0(char,HBB_BLOCKSIZE);len=fread(msgbuf,1,HBB_BLOCKSIZE-1,fd);fclose(fd);next_utf8_char=msgbuf;// Check there is no binary data. It must be a *message* file!for(p=msgbuf;*p;p++){if(utf8_mode){if(p==next_utf8_char){if(!iswprint(get_char(p))&&*p!='\n'&&*p!='\t')break;next_utf8_char=next_char(p);}}else{unsignedcharsc=*p;if(!iswprint(sc)&&sc!='\n'&&sc!='\t')break;}}if(*p||(size_t)(p-msgbuf)!=len){// We're not at the End Of Line...scr_LogPrint(LPRINT_LOGNORM,"Message file contains ""invalid characters (%s)",filename);g_free(msgbuf);returnNULL;}// p is now at the EOL// Let's strip trailing newlinesif(p>msgbuf)p--;while(p>msgbuf&&*p=='\n')*p--=0;// It could be empty, once the trailing newlines are goneif(p==msgbuf&&*p=='\n'){scr_LogPrint(LPRINT_LOGNORM,"Message file is empty (%s)",filename);g_free(msgbuf);returnNULL;}msgbuf_utf8=to_utf8(msgbuf);if(!msgbuf_utf8&&msgbuf)scr_LogPrint(LPRINT_LOGNORM,"Message file charset conversion error (%s)",filename);g_free(msgbuf);returnmsgbuf_utf8;}staticvoiddo_say_to(char*arg){char**paramlst;char*fjid,*msg_utf8;char*msg;char*unescaped_msg=NULL;char*uncompletedfjid=NULL;char*file=NULL;LmMessageSubTypemsg_type=LM_MESSAGE_SUB_TYPE_NOT_SET;boolquiet=FALSE;booleval=FALSE;if(!xmpp_is_online()){scr_LogPrint(LPRINT_NORMAL,"You are not connected.");return;}msg_type=scan_mtype(&arg);paramlst=split_arg(arg,2,1);// jid, message (or option, jid, message)if(!*paramlst){// No parameter?scr_LogPrint(LPRINT_NORMAL,"Please specify a Jabber ID.");free_arg_lst(paramlst);return;}// Check for an option parameterwhile(*paramlst){if(!strcmp(*paramlst,"-q")){char**oldparamlst=paramlst;paramlst=split_arg(*(oldparamlst+1),2,1);// jid, messagefree_arg_lst(oldparamlst);quiet=TRUE;}elseif(!strcmp(*paramlst,"-e")){char**oldparamlst=paramlst;paramlst=split_arg(*(oldparamlst+1),2,1);// jid, messagefree_arg_lst(oldparamlst);eval=TRUE;}elseif(!strcmp(*paramlst,"-f")){char**oldparamlst=paramlst;paramlst=split_arg(*(oldparamlst+1),2,1);// filename, jidfree_arg_lst(oldparamlst);if(!*paramlst){scr_LogPrint(LPRINT_NORMAL,"Wrong usage.");free_arg_lst(paramlst);return;}file=g_strdup(*paramlst);// One more parameter shift...oldparamlst=paramlst;paramlst=split_arg(*(oldparamlst+1),2,1);// jid, nothingfree_arg_lst(oldparamlst);}else{break;}}if(!*paramlst){scr_LogPrint(LPRINT_NORMAL,"Wrong usage.");free_arg_lst(paramlst);return;}fjid=*paramlst;msg=*(paramlst+1);if(fjid[0]=='.'){constgchar*cjid=(current_buddy?CURRENT_JID:NULL);if(fjid[1]=='\0'){fjid=g_strdup(cjid);}elseif(fjid[1]==JID_RESOURCE_SEPARATOR){if(!cjid){fjid=NULL;}else{char*res_utf8=to_utf8(fjid+2);fjid=g_strdup_printf("%s%c%s",cjid,JID_RESOURCE_SEPARATOR,res_utf8);g_free(res_utf8);}}else{fjid=to_utf8(fjid);}}else{fjid=to_utf8(fjid);}if(!fjid){scr_LogPrint(LPRINT_NORMAL,"The Jabber ID is invalid.");free_arg_lst(paramlst);return;}if(!strchr(fjid,JID_DOMAIN_SEPARATOR)){constgchar*append_server=settings_opt_get("default_server");if(append_server){gchar*res=strchr(fjid,JID_RESOURCE_SEPARATOR);uncompletedfjid=fjid;if(res){*res++='\0';fjid=g_strdup_printf("%s%c%s%c%s",fjid,JID_DOMAIN_SEPARATOR,append_server,JID_RESOURCE_SEPARATOR,res);}else{fjid=g_strdup_printf("%s%c%s",fjid,JID_DOMAIN_SEPARATOR,append_server);}}}if(check_jid_syntax(fjid)){scr_LogPrint(LPRINT_NORMAL,"Please specify a valid Jabber ID.");free_arg_lst(paramlst);g_free(uncompletedfjid);g_free(fjid);return;}if(!file){msg_utf8=to_utf8(msg);if(eval){unescaped_msg=ut_unescape_tabs_cr(msg_utf8);// We must not free() if the original string was returnedif(unescaped_msg==msg_utf8)unescaped_msg=NULL;}msg=(unescaped_msg?unescaped_msg:msg_utf8);}else{char*filename_xp;if(msg)scr_LogPrint(LPRINT_NORMAL,"say_to: extra parameter ignored.");filename_xp=expand_filename(file);msg=msg_utf8=load_message_from_file(filename_xp);g_free(filename_xp);g_free(file);}send_message_to(fjid,msg,NULL,msg_type,quiet);g_free(uncompletedfjid);g_free(fjid);g_free(msg_utf8);g_free(unescaped_msg);free_arg_lst(paramlst);}// buffer_updown(updown, nblines)// updown: -1=up, +1=downinlinestaticvoidbuffer_updown(intupdown,char*nlines){intnblines;if(!nlines||!*nlines)nblines=0;elsenblines=strtol(nlines,NULL,10);if(nblines>=0)scr_buffer_scroll_up_down(updown,nblines);}staticvoidbuffer_search(intdirection,char*arg){if(!arg||!*arg){scr_LogPrint(LPRINT_NORMAL,"Missing parameter.");return;}scr_buffer_search(direction,arg);}staticvoidbuffer_date(char*date){time_tt;if(!date||!*date){scr_LogPrint(LPRINT_NORMAL,"Missing parameter.");return;}strip_arg_special_chars(date);t=from_iso8601(date,0);if(t)scr_buffer_date(t);elsescr_LogPrint(LPRINT_NORMAL,"The date you specified is ""not correctly formatted or invalid.");}staticvoidbuffer_percent(char*arg1,char*arg2){// Basically, user has typed "%arg1 arg2"// "%50" -> arg1 = 50, arg2 null pointer// "% 50" -> arg1 = \0, arg2 = 50if(!*arg1&&(!arg2||!*arg2)){// No valuescr_LogPrint(LPRINT_NORMAL,"Missing parameter.");return;}if(*arg1&&arg2&&*arg2){// Two valuesscr_LogPrint(LPRINT_NORMAL,"Wrong parameters.");return;}scr_buffer_percent(atoi((*arg1?arg1:arg2)));}staticvoiddo_buffer(char*arg){char**paramlst;char*subcmd;if(!current_buddy)return;paramlst=split_arg(arg,2,1);// subcmd, argsubcmd=*paramlst;arg=*(paramlst+1);if(!subcmd||!*subcmd){scr_LogPrint(LPRINT_NORMAL,"Missing parameter.");free_arg_lst(paramlst);return;}if(buddy_gettype(BUDDATA(current_buddy))&ROSTER_TYPE_GROUP&&strcasecmp(subcmd,"close_all")){scr_LogPrint(LPRINT_NORMAL,"Groups have no buffer.");free_arg_lst(paramlst);return;}if(!strcasecmp(subcmd,"top")){scr_buffer_top_bottom(-1);}elseif(!strcasecmp(subcmd,"bottom")){scr_buffer_top_bottom(1);}elseif(!strcasecmp(subcmd,"clear")){scr_buffer_clear();}elseif(!strcasecmp(subcmd,"close")){scr_buffer_purge(1,arg);}elseif(!strcasecmp(subcmd,"close_all")){scr_buffer_purge_all(1);}elseif(!strcasecmp(subcmd,"purge")){scr_buffer_purge(0,arg);}elseif(!strcasecmp(subcmd,"scroll_lock")){scr_buffer_scroll_lock(1);}elseif(!strcasecmp(subcmd,"scroll_unlock")){scr_buffer_scroll_lock(0);}elseif(!strcasecmp(subcmd,"scroll_toggle")){scr_buffer_scroll_lock(-1);}elseif(!strcasecmp(subcmd,"up")){buffer_updown(-1,arg);}elseif(!strcasecmp(subcmd,"down")){buffer_updown(1,arg);}elseif(!strcasecmp(subcmd,"search_backward")){strip_arg_special_chars(arg);buffer_search(-1,arg);}elseif(!strcasecmp(subcmd,"search_forward")){strip_arg_special_chars(arg);buffer_search(1,arg);}elseif(!strcasecmp(subcmd,"date")){buffer_date(arg);}elseif(*subcmd=='%'){buffer_percent(subcmd+1,arg);}elseif(!strcasecmp(subcmd,"save")){scr_buffer_dump(arg);}elseif(!strcasecmp(subcmd,"list")){scr_buffer_list();}elseif(!strcasecmp(subcmd,"readmark")){scr_buffer_jump_readmark();}else{scr_LogPrint(LPRINT_NORMAL,"Unrecognized parameter!");}free_arg_lst(paramlst);}staticvoiddo_clear(char*arg)// Alias for "buffer clear"{do_buffer("clear");}staticvoiddo_info(char*arg){gpointerbud;constchar*bjid,*name;guinttype,on_srv;char*buffer;enumsubscresub;if(!current_buddy)return;bud=BUDDATA(current_buddy);bjid=buddy_getjid(bud);name=buddy_getname(bud);type=buddy_gettype(bud);esub=buddy_getsubscription(bud);on_srv=buddy_getonserverflag(bud);buffer=g_new(char,4096);if(bjid){GSList*resources,*p_res;char*bstr="unknown";// Enter chat modescr_set_chatmode(TRUE);scr_show_buddy_window();snprintf(buffer,4095,"jid: <%s>",bjid);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO,0);if(name){snprintf(buffer,4095,"Name: %s",name);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO,0);}if(type==ROSTER_TYPE_USER)bstr="user";elseif(type==ROSTER_TYPE_ROOM)bstr="chatroom";elseif(type==ROSTER_TYPE_AGENT)bstr="agent";snprintf(buffer,127,"Type: %s",bstr);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO,0);if(!on_srv){scr_WriteIncomingMessage(bjid,"(Local item, not on the server)",0,HBB_PREFIX_INFO,0);}if(esub==sub_both)bstr="both";elseif(esub&sub_from)bstr="from";elseif(esub&sub_to)bstr="to";elsebstr="none";snprintf(buffer,64,"Subscription: %s",bstr);if(esub&sub_pending)strcat(buffer," (pending)");scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO,0);resources=buddy_getresources(bud);if(!resources&&type==ROSTER_TYPE_USER){// No resource; display last status message, if any.constchar*rst_msg=buddy_getstatusmsg(bud,"");if(rst_msg){snprintf(buffer,4095,"Last status message: %s",rst_msg);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO,0);}}for(p_res=resources;p_res;p_res=g_slist_next(p_res)){gcharrprio;enumimstatusrstatus;constchar*rst_msg;time_trst_time;rprio=buddy_getresourceprio(bud,p_res->data);rstatus=buddy_getstatus(bud,p_res->data);rst_msg=buddy_getstatusmsg(bud,p_res->data);rst_time=buddy_getstatustime(bud,p_res->data);snprintf(buffer,4095,"Resource: [%c] (%d) %s",imstatus2char[rstatus],rprio,(char*)p_res->data);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO,0);if(rst_msg){snprintf(buffer,4095,"Status message: %s",rst_msg);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO|HBB_PREFIX_CONT,0);}if(rst_time){chartbuf[128];strftime(tbuf,sizeof(tbuf),"%Y-%m-%d %H:%M:%S",localtime(&rst_time));snprintf(buffer,127,"Status timestamp: %s",tbuf);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO|HBB_PREFIX_CONT,0);}#ifdef HAVE_GPGMEstructpgp_data*rpgp=buddy_resource_pgp(bud,p_res->data);if(rpgp&&rpgp->sign_keyid){snprintf(buffer,4095,"PGP key id: %s",rpgp->sign_keyid);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO|HBB_PREFIX_CONT,0);if(rpgp->last_sigsum){gpgme_sigsum_tss=rpgp->last_sigsum;snprintf(buffer,4095,"Last PGP signature: %s",(ss&GPGME_SIGSUM_GREEN?"good":(ss&GPGME_SIGSUM_RED?"bad":"unknown")));scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO|HBB_PREFIX_CONT,0);}}#endifg_free(p_res->data);}g_slist_free(resources);}else{/* Item has no jid */if(name)scr_LogPrint(LPRINT_NORMAL,"Name: %s",name);scr_LogPrint(LPRINT_NORMAL,"Type: %s",type==ROSTER_TYPE_GROUP?"group":(type==ROSTER_TYPE_SPECIAL?"special":"unknown"));}g_free(buffer);// Tell the user if this item has an annotation.if(type==ROSTER_TYPE_USER||type==ROSTER_TYPE_ROOM||type==ROSTER_TYPE_AGENT){structannotation*note=xmpp_get_storage_rosternotes(bjid,TRUE);if(note){// We do not display the note, we just tell the user.g_free(note->text);g_free(note->jid);g_free(note);scr_WriteIncomingMessage(bjid,"(This item has an annotation)",0,HBB_PREFIX_INFO,0);}}}// room_names() is a variation of do_info(), for chatrooms onlystaticvoidroom_names(gpointerbud,char*arg){constchar*bjid;char*buffer;GSList*resources,*p_res;enum{style_normal=0,style_detail,style_short,style_quiet,style_compact}style=0;intcnt=0;if(*arg){if(!strcasecmp(arg,"--short")){style=style_short;}elseif(!strcasecmp(arg,"--quiet")){style=style_quiet;}elseif(!strcasecmp(arg,"--detail")){style=style_detail;}elseif(!strcasecmp(arg,"--compact")){style=style_compact;}else{scr_LogPrint(LPRINT_NORMAL,"Unrecognized parameter!");return;}}// Enter chat modescr_set_chatmode(TRUE);scr_show_buddy_window();bjid=buddy_getjid(bud);buffer=g_new(char,4096);strncpy(buffer,"Room members:",127);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO,0);resources=buddy_getresources(bud);for(p_res=resources;p_res;p_res=g_slist_next(p_res)){enumimstatusrstatus;constchar*rst_msg;cnt++;rstatus=buddy_getstatus(bud,p_res->data);rst_msg=buddy_getstatusmsg(bud,p_res->data);if(style==style_short){snprintf(buffer,4095,"[%c] %s%s%s",imstatus2char[rstatus],(char*)p_res->data,rst_msg?" -- ":"",rst_msg?rst_msg:"");scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO,0);}elseif(style==style_compact){enumimrolerole=buddy_getrole(bud,p_res->data);enumimaffiliationaffil=buddy_getaffil(bud,p_res->data);boolshowaffil=(affil!=affil_none);snprintf(buffer,4095,"[%c] %s (%s%s%s)",imstatus2char[rstatus],(char*)p_res->data,showaffil?straffil[affil]:"\0",showaffil?"/":"\0",strrole[role]);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO,0);}else{// (Style "normal", "detail" or "quiet")snprintf(buffer,4095,"[%c] %s",imstatus2char[rstatus],(char*)p_res->data);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO,0);if(rst_msg&&style!=style_quiet){snprintf(buffer,4095,"Status message: %s",rst_msg);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO|HBB_PREFIX_CONT,0);}if(style==style_detail){enumimrolerole=buddy_getrole(bud,p_res->data);enumimaffiliationaffil=buddy_getaffil(bud,p_res->data);snprintf(buffer,4095,"Role: %s",strrole[role]);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO|HBB_PREFIX_CONT,0);if(affil!=affil_none){snprintf(buffer,4095,"Affiliat.: %s",straffil[affil]);scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO|HBB_PREFIX_CONT,0);}}}g_free(p_res->data);}snprintf(buffer,4095,"Total: %d member%c",cnt,cnt>1?'s':'\0');scr_WriteIncomingMessage(bjid,buffer,0,HBB_PREFIX_INFO,0);g_slist_free(resources);g_free(buffer);}staticvoidmove_group_member(gpointerbud,void*groupnamedata){constchar*bjid,*name,*groupname;guinttype,on_srv;groupname=(char*)groupnamedata;bjid=buddy_getjid(bud);name=buddy_getname(bud);type=buddy_gettype(bud);on_srv=buddy_getonserverflag(bud);if(on_srv){xmpp_updatebuddy(bjid,name,*groupname?groupname:NULL);}else{buddy_setgroup(bud,(char*)groupname);if((type&ROSTER_TYPE_ROOM)&&xmpp_is_bookmarked(bjid)&&settings_opt_get_int("muc_bookmark_autoupdate"))room_bookmark(bud,NULL);}}staticvoiddo_rename(char*arg){gpointerbud;constchar*bjid,*group;guinttype,on_srv;char*newname,*p;char*name_utf8;if(!current_buddy)return;bud=BUDDATA(current_buddy);bjid=buddy_getjid(bud);group=buddy_getgroupname(bud);type=buddy_gettype(bud);on_srv=buddy_getonserverflag(bud);if(type&ROSTER_TYPE_SPECIAL){scr_LogPrint(LPRINT_NORMAL,"You can't rename this item.");return;}if(!*arg&&!(type&ROSTER_TYPE_GROUP)){scr_LogPrint(LPRINT_NORMAL,"Please specify a new name.");return;}//if (!(type & ROSTER_TYPE_GROUP) && !on_srv) {// scr_LogPrint(LPRINT_NORMAL,// "Note: this item will be added to your server roster.");// // If this is a MUC room w/o bookmark, let's give a small hint...// if ((type & ROSTER_TYPE_ROOM) && !xmpp_is_bookmarked(bjid)) {// scr_LogPrint(LPRINT_NORMAL,// "You should add a room bookmark or it will not be "// "recognized as a MUC room next time you run mcabber.");// }//}newname=g_strdup(arg);// Remove trailing spacefor(p=newname;*p;p++);while(p>newname&&*p==' ')*p=0;strip_arg_special_chars(newname);name_utf8=to_utf8(newname);if(type&ROSTER_TYPE_GROUP){// Rename a whole groupforeach_group_member(bud,&move_group_member,name_utf8);// Let's jump to the previous buddy, because this group name should// disappear when we receive the server answer.scr_roster_up_down(-1,1);}else{// Rename a single buddyguintdel_name=0;if(!*newname||!strcmp(arg,"-"))del_name=TRUE;if(on_srv){/* We do not rename the buddy right now because the server could reject * the request. Let's wait for the server answer. */xmpp_updatebuddy(bjid,(del_name?NULL:name_utf8),group&&*group?group:NULL);}else{// This is a local item, we rename it without adding to roster.buddy_setname(bud,(del_name?(char*)bjid:name_utf8));if((type&ROSTER_TYPE_ROOM)&&xmpp_is_bookmarked(bjid)&&settings_opt_get_int("muc_bookmark_autoupdate"))room_bookmark(bud,NULL);}}g_free(name_utf8);g_free(newname);update_roster=TRUE;}staticvoiddo_move(char*arg){gpointerbud;constchar*bjid,*name,*oldgroupname;guinttype,on_srv;char*newgroupname,*p;char*group_utf8;if(!current_buddy)return;bud=BUDDATA(current_buddy);bjid=buddy_getjid(bud);name=buddy_getname(bud);type=buddy_gettype(bud);on_srv=buddy_getonserverflag(bud);oldgroupname=buddy_getgroupname(bud);if(type&ROSTER_TYPE_GROUP){scr_LogPrint(LPRINT_NORMAL,"You can't move groups!");return;}if(type&ROSTER_TYPE_SPECIAL){scr_LogPrint(LPRINT_NORMAL,"You can't move this item.");return;}newgroupname=g_strdup(arg);// Remove trailing spacefor(p=newgroupname;*p;p++);while(p>newgroupname&&*p==' ')*p--=0;strip_arg_special_chars(newgroupname);group_utf8=to_utf8(newgroupname);if(strcmp(oldgroupname,group_utf8)){if(on_srv){xmpp_updatebuddy(bjid,name,*group_utf8?group_utf8:NULL);scr_roster_up_down(-1,1);/* We do not move the buddy right now because the server could reject * the request. Let's wait for the server answer. */}else{// This is a local item, we move it without adding to roster.guintmsgflag;// If the buddy has a pending message flag,// we remove it temporarily in order to reset the global group// flag. We set it back once the room is in the new group,// which will update the new group's flag.msgflag=buddy_getflags(bud)&ROSTER_FLAG_MSG;if(msgflag)roster_msg_setflag(bjid,FALSE,FALSE);buddy_setgroup(bud,group_utf8);if(msgflag)roster_msg_setflag(bjid,FALSE,TRUE);if((type&ROSTER_TYPE_ROOM)&&xmpp_is_bookmarked(bjid)&&settings_opt_get_int("muc_bookmark_autoupdate"))room_bookmark(bud,NULL);}}g_free(group_utf8);g_free(newgroupname);update_roster=TRUE;}staticvoidlist_option_cb(char*k,char*v,void*f){if(strncmp(k,"password",8)&&strcmp(k,"pgp_passphrase")){GSList**list=f;*list=g_slist_insert_sorted(*list,k,(GCompareFunc)strcmp);}}staticvoiddo_set(char*arg){guintassign;gchar*option,*value;gchar*option_utf8;if(!*arg){// List all set optionsgsizemax=0;gsizemaxmax=scr_gettextwidth()/3;GSList*lel;gchar*format;GSList*list=NULL;// Get sorted list of keyssettings_foreach(SETTINGS_TYPE_OPTION,list_option_cb,&list);if(!list){scr_LogPrint(LPRINT_NORMAL,"No options found.");return;}// Find out maximum key lengthfor(lel=list;lel;lel=lel->next){constgchar*key=lel->data;gsizelen=strlen(key);if(len>max){max=len;if(max>maxmax){max=maxmax;break;}}}// Print out list of optionsformat=g_strdup_printf("%%-%us = [%%s]",(unsigned)max);for(lel=list;lel;lel=lel->next){constgchar*key=lel->data;scr_LogPrint(LPRINT_NORMAL,format,key,settings_opt_get(key));}g_free(format);scr_setmsgflag_if_needed(SPECIAL_BUFFER_STATUS_ID,TRUE);scr_setattentionflag_if_needed(SPECIAL_BUFFER_STATUS_ID,TRUE,ROSTER_UI_PRIO_STATUS_WIN_MESSAGE,prio_max);return;}assign=parse_assigment(arg,&option,&value);if(!option){scr_LogPrint(LPRINT_NORMAL,"Set what option?");return;}option_utf8=to_utf8(option);g_free(option);if(!assign){// This is a queryconstgchar*val=settings_opt_get(option_utf8);if(val){if(g_ascii_strncasecmp(option_utf8,"password",8)==0||g_ascii_strcasecmp(option_utf8,"pgp_passphrase")==0)val="***";scr_LogPrint(LPRINT_NORMAL,"%s = [%s]",option_utf8,val);}else{scr_LogPrint(LPRINT_NORMAL,"Option %s is not set",option_utf8);}g_free(option_utf8);return;}// Update the option// Maybe some options should be protected when user is connected (server,// username, etc.). And we should catch some options here, too// (hide_offline_buddies for ex.)if(!value){settings_del(SETTINGS_TYPE_OPTION,option_utf8);}else{gchar*value_utf8=to_utf8(value);settings_set(SETTINGS_TYPE_OPTION,option_utf8,value_utf8);g_free(value_utf8);g_free(value);}g_free(option_utf8);}staticvoiddump_alias(char*k,char*v,void*param){scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"Alias %s = %s",k,v);scr_setmsgflag_if_needed(SPECIAL_BUFFER_STATUS_ID,TRUE);scr_setattentionflag_if_needed(SPECIAL_BUFFER_STATUS_ID,TRUE,ROSTER_UI_PRIO_STATUS_WIN_MESSAGE,prio_max);}staticvoiddo_alias(char*arg){guintassign;gchar*alias,*value;assign=parse_assigment(arg,&alias,&value);if(!alias){settings_foreach(SETTINGS_TYPE_ALIAS,&dump_alias,NULL);update_roster=TRUE;return;}if(!assign){// This is a queryconstchar*val=settings_get(SETTINGS_TYPE_ALIAS,alias);// NOTE: LPRINT_NOTUTF8 here, see below why it isn't encoded...if(val)scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"%s = %s",alias,val);elsescr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"Alias '%s' does not exist",alias);gotodo_alias_return;}// Check the alias does not conflict with a registered commandif(cmd_get(alias)){scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"'%s' is a reserved word!",alias);gotodo_alias_return;}// Update the aliasif(!value){if(settings_get(SETTINGS_TYPE_ALIAS,alias)){settings_del(SETTINGS_TYPE_ALIAS,alias);// Remove alias from the completion listcompl_del_category_word(COMPL_CMD,alias);}}else{/* Add alias to the completion list, if not already in. NOTE: We're not UTF8-encoding "alias" and "value" here because UTF-8 is not yet supported in the UI... (and we use the values in the completion system) */if(!settings_get(SETTINGS_TYPE_ALIAS,alias))compl_add_category_word(COMPL_CMD,alias);settings_set(SETTINGS_TYPE_ALIAS,alias,value);g_free(value);}do_alias_return:g_free(alias);}staticvoiddump_bind(char*k,char*v,void*param){scr_LogPrint(LPRINT_NORMAL,"Key %4s is bound to: %s",k,v);}staticvoiddo_bind(char*arg){guintassign;gchar*k_code,*value;assign=parse_assigment(arg,&k_code,&value);if(!k_code){settings_foreach(SETTINGS_TYPE_BINDING,&dump_bind,NULL);scr_setmsgflag_if_needed(SPECIAL_BUFFER_STATUS_ID,TRUE);scr_setattentionflag_if_needed(SPECIAL_BUFFER_STATUS_ID,TRUE,ROSTER_UI_PRIO_STATUS_WIN_MESSAGE,prio_max);return;}if(!assign){// This is a queryconstchar*val=settings_get(SETTINGS_TYPE_BINDING,k_code);if(val)scr_LogPrint(LPRINT_NORMAL,"Key %s is bound to: %s",k_code,val);elsescr_LogPrint(LPRINT_NORMAL,"Key %s is not bound.",k_code);g_free(k_code);return;}// Update the key bindingif(!value){settings_del(SETTINGS_TYPE_BINDING,k_code);}else{gchar*value_utf8=to_utf8(value);settings_set(SETTINGS_TYPE_BINDING,k_code,value_utf8);g_free(value_utf8);g_free(value);}g_free(k_code);}staticvoiddo_quit(char*arg){mcabber_set_terminate_ui();}staticvoiddo_rawxml(char*arg){char**paramlst;char*subcmd;if(!xmpp_is_online()){scr_LogPrint(LPRINT_NORMAL,"You are not connected.");return;}paramlst=split_arg(arg,2,1);// subcmd, argsubcmd=*paramlst;arg=*(paramlst+1);if(!subcmd||!*subcmd){scr_LogPrint(LPRINT_NORMAL,"Please read the manual page"" before using /rawxml :-)");free_arg_lst(paramlst);return;}if(!strcasecmp(subcmd,"send")){gchar*buffer;if(!subcmd||!*subcmd){scr_LogPrint(LPRINT_NORMAL,"Missing parameter.");free_arg_lst(paramlst);return;}// We don't strip_arg_special_chars() here, because it would be a pain for// the user to escape quotes in a XML stream...buffer=to_utf8(arg);if(buffer){scr_LogPrint(LPRINT_NORMAL,"Sending XML string");lm_connection_send_raw(lconnection,buffer,NULL);g_free(buffer);}else{scr_LogPrint(LPRINT_NORMAL,"Conversion error in XML string.");}}else{scr_LogPrint(LPRINT_NORMAL,"Unrecognized parameter!");}free_arg_lst(paramlst);}// check_room_subcommand(arg, param_needed, buddy_must_be_a_room)// - Check if this is a room, if buddy_must_be_a_room is not null// - Check there is at least 1 parameter, if param_needed is true// - Return null if one of the checks fails, or a pointer to the first// non-space character.staticchar*check_room_subcommand(char*arg,boolparam_needed,gpointerbuddy_must_be_a_room){if(buddy_must_be_a_room&&!(buddy_gettype(buddy_must_be_a_room)&ROSTER_TYPE_ROOM)){scr_LogPrint(LPRINT_NORMAL,"This isn't a conference room.");returnNULL;}if(param_needed){if(!arg){scr_LogPrint(LPRINT_NORMAL,"Missing parameter.");returnNULL;}}if(arg)returnarg;elsereturn"";}staticvoidroom_join(gpointerbud,char*arg){char**paramlst;char*roomname,*nick,*pass;char*roomname_tmp=NULL;char*pass_utf8;paramlst=split_arg(arg,3,0);// roomid, nickname, passwordroomname=*paramlst;nick=*(paramlst+1);pass=*(paramlst+2);if(!roomname)nick=NULL;if(!nick)pass=NULL;if(!roomname||!strcmp(roomname,".")){// If the current_buddy is recognized as a room, the room name// can be omitted (or "." can be used).if(!bud||!(buddy_gettype(bud)&ROSTER_TYPE_ROOM)){scr_LogPrint(LPRINT_NORMAL,"Please specify a room name.");free_arg_lst(paramlst);return;}roomname=(char*)buddy_getjid(bud);}elseif(strchr(roomname,'/')){scr_LogPrint(LPRINT_NORMAL,"Invalid room name.");free_arg_lst(paramlst);return;}else{// The room id has been specified. Let's convert it and use it.mc_strtolower(roomname);roomname=roomname_tmp=to_utf8(roomname);}// If no nickname is provided with the /join command,// we try to get a default nickname.if(!nick||!*nick)nick=default_muc_nickname(roomname);elsenick=to_utf8(nick);// If we still have no nickname, give upif(!nick||!*nick){scr_LogPrint(LPRINT_NORMAL,"Please specify a nickname.");g_free(nick);free_arg_lst(paramlst);return;}pass_utf8=to_utf8(pass);if(!pass){constchar*roompass=xmpp_get_bookmark_password(roomname);if(roompass)pass_utf8=g_strdup(roompass);}xmpp_room_join(roomname,nick,pass_utf8);scr_LogPrint(LPRINT_LOGNORM,"Sent a join request to <%s>...",roomname);g_free(roomname_tmp);g_free(nick);g_free(pass_utf8);buddylist_build();update_roster=TRUE;free_arg_lst(paramlst);}staticvoidroom_invite(gpointerbud,char*arg){char**paramlst;constgchar*roomname;char*fjid;gchar*reason_utf8;paramlst=split_arg(arg,2,1);// jid, [reason]fjid=*paramlst;arg=*(paramlst+1);// An empty reason is no reason...if(arg&&!*arg)arg=NULL;if(!fjid||!*fjid){scr_LogPrint(LPRINT_NORMAL,"Missing or incorrect Jabber ID.");free_arg_lst(paramlst);return;}roomname=buddy_getjid(bud);reason_utf8=to_utf8(arg);xmpp_room_invite(roomname,fjid,reason_utf8);scr_LogPrint(LPRINT_LOGNORM,"Invitation sent to <%s>.",fjid);g_free(reason_utf8);free_arg_lst(paramlst);}staticvoidroom_affil(gpointerbud,char*arg){char**paramlst;gchar*fjid,*rolename;structrole_affilra;constchar*roomid=buddy_getjid(bud);paramlst=split_arg(arg,3,1);// jid, new_affil, [reason]fjid=*paramlst;rolename=*(paramlst+1);arg=*(paramlst+2);if(!fjid||!*fjid||!rolename||!*rolename){scr_LogPrint(LPRINT_NORMAL,"Please specify both a Jabber ID and a role.");free_arg_lst(paramlst);return;}ra.type=type_affil;ra.val.affil=affil_none;for(;ra.val.affil<imaffiliation_size;ra.val.affil++)if(!strcasecmp(rolename,straffil[ra.val.affil]))break;if(ra.val.affil<imaffiliation_size){gchar*jid_utf8,*reason_utf8;jid_utf8=to_utf8(fjid);reason_utf8=to_utf8(arg);xmpp_room_setattrib(roomid,jid_utf8,NULL,ra,reason_utf8);g_free(jid_utf8);g_free(reason_utf8);}else{scr_LogPrint(LPRINT_NORMAL,"Wrong affiliation parameter.");}free_arg_lst(paramlst);}staticvoidroom_role(gpointerbud,char*arg){char**paramlst;gchar*nick,*rolename;structrole_affilra;constchar*roomid=buddy_getjid(bud);paramlst=split_arg(arg,3,1);// nick, new_role, [reason]nick=*paramlst;rolename=*(paramlst+1);arg=*(paramlst+2);if(!nick||!*nick||!rolename||!*rolename){scr_LogPrint(LPRINT_NORMAL,"Please specify both a nickname and a role.");free_arg_lst(paramlst);return;}ra.type=type_role;ra.val.role=role_none;for(;ra.val.role<imrole_size;ra.val.role++)if(!strcasecmp(rolename,strrole[ra.val.role]))break;if(ra.val.role<imrole_size){gchar*nick_utf8,*reason_utf8;nick_utf8=to_utf8(nick);reason_utf8=to_utf8(arg);xmpp_room_setattrib(roomid,NULL,nick_utf8,ra,reason_utf8);g_free(nick_utf8);g_free(reason_utf8);}else{scr_LogPrint(LPRINT_NORMAL,"Wrong role parameter.");}free_arg_lst(paramlst);}// The expected argument is a Jabber idstaticvoidroom_ban(gpointerbud,char*arg){char**paramlst;gchar*fjid,*bjid;constgchar*banjid;gchar*jid_utf8,*reason_utf8;structrole_affilra;constchar*roomid=buddy_getjid(bud);paramlst=split_arg(arg,2,1);// jid, [reason]fjid=*paramlst;arg=*(paramlst+1);if(!fjid||!*fjid){scr_LogPrint(LPRINT_NORMAL,"Please specify a Jabber ID.");free_arg_lst(paramlst);return;}ra.type=type_affil;ra.val.affil=affil_outcast;bjid=jidtodisp(fjid);jid_utf8=to_utf8(bjid);// If the argument doesn't look like a jid, we'll try to find a matching// nickname.if(!strchr(bjid,JID_DOMAIN_SEPARATOR)||check_jid_syntax(bjid)){constgchar*tmp;// We want the initial argument, so the fjid variable, because// we don't want to strip a resource-like string from the nickname!g_free(jid_utf8);jid_utf8=to_utf8(fjid);tmp=buddy_getrjid(bud,jid_utf8);if(!tmp){scr_LogPrint(LPRINT_NORMAL,"Wrong JID or nickname");gotoroom_ban_return;}banjid=jidtodisp(tmp);}else{banjid=jid_utf8;}scr_LogPrint(LPRINT_NORMAL,"Requesting a ban for %s",banjid);reason_utf8=to_utf8(arg);xmpp_room_setattrib(roomid,banjid,NULL,ra,reason_utf8);g_free(reason_utf8);room_ban_return:g_free(bjid);g_free(jid_utf8);free_arg_lst(paramlst);}// The expected argument is a Jabber idstaticvoidroom_unban(gpointerbud,char*arg){gchar*fjid=arg;gchar*jid_utf8;structrole_affilra;constchar*roomid=buddy_getjid(bud);if(!fjid||!*fjid){scr_LogPrint(LPRINT_NORMAL,"Please specify a Jabber ID.");return;}ra.type=type_affil;ra.val.affil=affil_none;jid_utf8=to_utf8(fjid);xmpp_room_setattrib(roomid,jid_utf8,NULL,ra,NULL);g_free(jid_utf8);}// The expected argument is a nicknamestaticvoidroom_kick(gpointerbud,char*arg){char**paramlst;gchar*nick;gchar*nick_utf8,*reason_utf8;structrole_affilra;constchar*roomid=buddy_getjid(bud);paramlst=split_arg(arg,2,1);// nickname, [reason]nick=*paramlst;arg=*(paramlst+1);if(!nick||!*nick){scr_LogPrint(LPRINT_NORMAL,"Please specify a nickname.");free_arg_lst(paramlst);return;}ra.type=type_role;ra.val.role=role_none;nick_utf8=to_utf8(nick);reason_utf8=to_utf8(arg);xmpp_room_setattrib(roomid,NULL,nick_utf8,ra,reason_utf8);g_free(nick_utf8);g_free(reason_utf8);free_arg_lst(paramlst);}voidcmd_room_leave(gpointerbud,char*arg){gchar*roomid,*desc;constchar*nickname;nickname=buddy_getnickname(bud);if(!nickname){scr_LogPrint(LPRINT_NORMAL,"You are not in this room.");return;}roomid=g_strdup_printf("%s/%s",buddy_getjid(bud),nickname);desc=to_utf8(arg);xmpp_setstatus(offline,roomid,desc,TRUE);g_free(desc);g_free(roomid);}staticvoidroom_nick(gpointerbud,char*arg){if(!buddy_getinsideroom(bud)){scr_LogPrint(LPRINT_NORMAL,"You are not in this room.");return;}if(!arg||!*arg){constchar*nick=buddy_getnickname(bud);if(nick)scr_LogPrint(LPRINT_NORMAL,"Your nickname is: %s",nick);elsescr_LogPrint(LPRINT_NORMAL,"You have no nickname in this room.");}else{gchar*nick=to_utf8(arg);strip_arg_special_chars(nick);xmpp_room_join(buddy_getjid(bud),nick,NULL);g_free(nick);}}staticvoidroom_privmsg(gpointerbud,char*arg){char**paramlst;gchar*fjid_utf8,*nick,*nick_utf8,*msg;paramlst=split_arg(arg,2,1);// nickname, messagenick=*paramlst;arg=*(paramlst+1);if(!nick||!*nick||!arg||!*arg){scr_LogPrint(LPRINT_NORMAL,"Please specify both a Jabber ID and a message.");free_arg_lst(paramlst);return;}nick_utf8=to_utf8(nick);fjid_utf8=g_strdup_printf("%s/%s",buddy_getjid(bud),nick_utf8);g_free(nick_utf8);msg=to_utf8(arg);send_message_to(fjid_utf8,msg,NULL,LM_MESSAGE_SUB_TYPE_NOT_SET,FALSE);g_free(fjid_utf8);g_free(msg);free_arg_lst(paramlst);}staticvoidroom_remove(gpointerbud,char*arg){if(*arg){scr_LogPrint(LPRINT_NORMAL,"This action does not require a parameter; ""the currently-selected room will be removed.");return;}// Quick check: if there are resources, we haven't leftif(buddy_getinsideroom(bud)){scr_LogPrint(LPRINT_NORMAL,"You haven't left this room!");return;}// Delete the roomroster_del_user(buddy_getjid(bud));scr_update_buddy_window();buddylist_build();update_roster=TRUE;}staticvoidroom_topic(gpointerbud,char*arg){if(!buddy_getinsideroom(bud)){scr_LogPrint(LPRINT_NORMAL,"You are not in this room.");return;}// If no parameter is given, display the current topicif(!*arg){constchar*topic=buddy_gettopic(bud);if(topic)scr_LogPrint(LPRINT_NORMAL,"Topic: %s",topic);elsescr_LogPrint(LPRINT_NORMAL,"No topic has been set.");return;}// If arg is "-", let's clear the topicif(!g_strcmp0(arg,"-"))arg=NULL;arg=to_utf8(arg);// If arg is not NULL & option is set, unescape itif(arg){char*unescaped_topic=NULL;if(!strncmp(arg,"-u ",3)){char*tmp=arg;arg=g_strdup(arg+3);g_free(tmp);unescaped_topic=ut_unescape_tabs_cr(arg);// We must not free() if the original string was returnedif(unescaped_topic==arg){unescaped_topic=NULL;}elseif(unescaped_topic!=NULL){g_free(arg);arg=unescaped_topic;}}}// Set the topicxmpp_send_msg(buddy_getjid(bud),NULL,ROSTER_TYPE_ROOM,arg?arg:"",FALSE,NULL,LM_MESSAGE_SUB_TYPE_NOT_SET,NULL);g_free(arg);}staticvoidroom_destroy(gpointerbud,char*arg){gchar*msg;if(arg&&*arg)msg=to_utf8(arg);elsemsg=NULL;xmpp_room_destroy(buddy_getjid(bud),NULL,msg);g_free(msg);}staticvoidroom_unlock(gpointerbud,char*arg){if(*arg){scr_LogPrint(LPRINT_NORMAL,"Unknown parameter.");return;}xmpp_room_unlock(buddy_getjid(bud));}staticvoidroom_setopt(gpointerbud,char*arg){char**paramlst;char*param,*value;enum{opt_none=0,opt_printstatus,opt_autowhois,opt_flagjoins}option=0;guintchanged=0;paramlst=split_arg(arg,2,1);// param, valueparam=*paramlst;value=*(paramlst+1);if(!param){scr_LogPrint(LPRINT_NORMAL,"Please specify a room option.");free_arg_lst(paramlst);return;}if(!strcasecmp(param,"print_status")){option=opt_printstatus;}elseif(!strcasecmp(param,"auto_whois")){option=opt_autowhois;}elseif(!strcasecmp(param,"flag_joins")){option=opt_flagjoins;}else{scr_LogPrint(LPRINT_NORMAL,"Wrong option!");free_arg_lst(paramlst);return;}// If no value is given, display the current valueif(!value){constchar*strval;if(option==opt_printstatus)strval=strprintstatus[buddy_getprintstatus(bud)];elseif(option==opt_autowhois)strval=strautowhois[buddy_getautowhois(bud)];elsestrval=strflagjoins[buddy_getflagjoins(bud)];scr_LogPrint(LPRINT_NORMAL,"%s is set to: %s",param,strval);free_arg_lst(paramlst);return;}if(option==opt_printstatus){enumroom_printstatuseval;if(!strcasecmp(value,"none")){eval=status_none;}elseif(!strcasecmp(value,"in_and_out")){eval=status_in_and_out;}elseif(!strcasecmp(value,"all")){eval=status_all;}else{eval=status_default;if(strcasecmp(value,"default")!=0)scr_LogPrint(LPRINT_NORMAL,"Unrecognized value, assuming default...");}if(eval!=buddy_getprintstatus(bud)){buddy_setprintstatus(bud,eval);changed=1;}}elseif(option==opt_autowhois){enumroom_autowhoiseval;if(!strcasecmp(value,"on")){eval=autowhois_on;}elseif(!strcasecmp(value,"off")){eval=autowhois_off;}else{eval=autowhois_default;if(strcasecmp(value,"default")!=0)scr_LogPrint(LPRINT_NORMAL,"Unrecognized value, assuming default...");}if(eval!=buddy_getautowhois(bud)){buddy_setautowhois(bud,eval);changed=1;}}elseif(option==opt_flagjoins){enumroom_flagjoinseval;if(!strcasecmp(value,"none")){eval=flagjoins_none;}elseif(!strcasecmp(value,"joins")){eval=flagjoins_joins;}elseif(!strcasecmp(value,"all")){eval=flagjoins_all;}else{eval=flagjoins_default;if(strcasecmp(value,"default")!=0)scr_LogPrint(LPRINT_NORMAL,"Unrecognized value, assuming default...");}if(eval!=buddy_getflagjoins(bud)){buddy_setflagjoins(bud,eval);changed=1;}}if(changed&&xmpp_is_bookmarked(buddy_getjid(bud))&&settings_opt_get_int("muc_bookmark_autoupdate"))room_bookmark(bud,NULL);free_arg_lst(paramlst);}// cmd_room_whois(..)// If interactive is TRUE, chatmode can be enabled.// Please note that usernick is expected in UTF-8 locale iff interactive is// FALSE (in order to work correctly with auto_whois).voidcmd_room_whois(gpointerbud,constchar*usernick,guintinteractive){char**paramlst=NULL;gchar*nick,*buffer;constchar*bjid,*realjid;constchar*rst_msg;gcharrprio;enumimstatusrstatus;enumimrolerole;enumimaffiliationaffil;time_trst_time;guintmsg_flag=HBB_PREFIX_INFO;if(interactive){paramlst=split_arg(usernick,1,0);// nicknamenick=to_utf8(*paramlst);}else{nick=g_strdup(usernick);}if(!nick||!*nick){scr_LogPrint(LPRINT_NORMAL,"Please specify a nickname.");if(paramlst)free_arg_lst(paramlst);return;}if(interactive){// Enter chat modescr_set_chatmode(TRUE);scr_show_buddy_window();}else{msg_flag|=HBB_PREFIX_NOFLAG;}bjid=buddy_getjid(bud);rstatus=buddy_getstatus(bud,nick);if(rstatus==offline){scr_LogPrint(LPRINT_NORMAL,"No such member: %s",nick);if(paramlst)free_arg_lst(paramlst);g_free(nick);return;}rst_time=buddy_getstatustime(bud,nick);rprio=buddy_getresourceprio(bud,nick);rst_msg=buddy_getstatusmsg(bud,nick);if(!rst_msg)rst_msg="";role=buddy_getrole(bud,nick);affil=buddy_getaffil(bud,nick);realjid=buddy_getrjid(bud,nick);buffer=g_new(char,4096);snprintf(buffer,4095,"Whois [%s]",nick);scr_WriteIncomingMessage(bjid,buffer,0,msg_flag,0);snprintf(buffer,4095,"Status : [%c] %s",imstatus2char[rstatus],rst_msg);scr_WriteIncomingMessage(bjid,buffer,0,msg_flag|HBB_PREFIX_CONT,0);if(rst_time){chartbuf[128];strftime(tbuf,sizeof(tbuf),"%Y-%m-%d %H:%M:%S",localtime(&rst_time));snprintf(buffer,127,"Timestamp: %s",tbuf);scr_WriteIncomingMessage(bjid,buffer,0,msg_flag|HBB_PREFIX_CONT,0);}if(realjid){snprintf(buffer,4095,"JID : <%s>",realjid);scr_WriteIncomingMessage(bjid,buffer,0,msg_flag|HBB_PREFIX_CONT,0);}snprintf(buffer,4095,"Role : %s",strrole[role]);scr_WriteIncomingMessage(bjid,buffer,0,msg_flag|HBB_PREFIX_CONT,0);snprintf(buffer,4095,"Affiliat.: %s",straffil[affil]);scr_WriteIncomingMessage(bjid,buffer,0,msg_flag|HBB_PREFIX_CONT,0);snprintf(buffer,4095,"Priority : %d",rprio);scr_WriteIncomingMessage(bjid,buffer,0,msg_flag|HBB_PREFIX_CONT,0);scr_WriteIncomingMessage(bjid,"End of WHOIS",0,msg_flag,0);g_free(buffer);g_free(nick);if(paramlst)free_arg_lst(paramlst);}staticvoidroom_bookmark(gpointerbud,char*arg){constchar*roomid;constchar*name=NULL,*nick=NULL,*passwd=NULL,*group=NULL;char*tmpnick=NULL;enumroom_autowhoisautowhois=0;enumroom_flagjoinsflagjoins=0;enumroom_printstatusprintstatus=0;enum{bm_add=0,bm_del=1}action=0;intautojoin=0,autojoin_set=0;intnick_set=0;if(arg&&*arg){// /room bookmark [add|del] [[+|-]autojoin] [-|nick]char**paramlst;char**pp;paramlst=split_arg(arg,4,0);// At most 4 parametersfor(pp=paramlst;*pp;pp++){if(!strcasecmp(*pp,"add"))action=bm_add;elseif(!strcasecmp(*pp,"del"))action=bm_del;elseif(!strcasecmp(*pp,"-autojoin")){autojoin=0;autojoin_set=1;}elseif(!strcasecmp(*pp,"+autojoin")||!strcasecmp(*pp,"autojoin")){autojoin=1;autojoin_set=1;}elseif(!strcmp(*pp,"-")){nick_set=1;}elseif(nick_set==0){nick_set=1;nick=tmpnick=to_utf8(*pp);}elseif(nick_set==1){passwd=to_utf8(*pp);}}free_arg_lst(paramlst);}roomid=buddy_getjid(bud);if(action==bm_add){name=buddy_getname(bud);if(!nick_set){nick=buddy_getnickname(bud);if(!nick)//we are probably bookmarking offline roomnick=xmpp_get_bookmark_nick(roomid);}if(!autojoin_set){autojoin=xmpp_get_bookmark_autojoin(roomid);}printstatus=buddy_getprintstatus(bud);autowhois=buddy_getautowhois(bud);flagjoins=buddy_getflagjoins(bud);group=buddy_getgroupname(bud);}xmpp_set_storage_bookmark(roomid,name,nick,passwd,autojoin,printstatus,autowhois,flagjoins,group);g_free(tmpnick);}staticvoiddisplay_all_bookmarks(void){GSList*bm,*bmp;GString*sbuf;structbookmark*bm_elt;bm=xmpp_get_all_storage_bookmarks();if(!bm)return;sbuf=g_string_new("");scr_WriteIncomingMessage(NULL,"List of MUC bookmarks:",0,HBB_PREFIX_INFO,0);for(bmp=bm;bmp;bmp=g_slist_next(bmp)){bm_elt=bmp->data;g_string_printf(sbuf,"%c <%s>",(bm_elt->autojoin?'*':' '),bm_elt->roomjid);if(bm_elt->nick)g_string_append_printf(sbuf," (%s)",bm_elt->nick);if(bm_elt->password)/* replace password for security reasons */g_string_append_printf(sbuf," (*****)");if(bm_elt->name)g_string_append_printf(sbuf," %s",bm_elt->name);g_free(bm_elt->roomjid);g_free(bm_elt->name);g_free(bm_elt->nick);g_free(bm_elt->password);g_free(bm_elt);scr_WriteIncomingMessage(NULL,sbuf->str,0,HBB_PREFIX_INFO|HBB_PREFIX_CONT,0);}scr_setmsgflag_if_needed(SPECIAL_BUFFER_STATUS_ID,TRUE);scr_setattentionflag_if_needed(SPECIAL_BUFFER_STATUS_ID,TRUE,ROSTER_UI_PRIO_STATUS_WIN_MESSAGE,prio_max);g_string_free(sbuf,TRUE);g_slist_free(bm);}staticvoiddo_module(char*arg){#ifdef MODULES_ENABLEgbooleanforce=FALSE;char**args;args=split_arg(arg,2,0);if(!args[0]||!strcmp(args[0],"list")){module_list_print();}else{constgchar*error=NULL;constgchar*name=args[1];if(name&&name[0]=='-'&&name[1]=='f'){force=TRUE;name+=2;while(*name&&*name==' ')++name;}if(!strcmp(args[0],"load")){error=module_load(name,TRUE,force);if(error)scr_log_print(LPRINT_LOGNORM,"Module '%s' loading error: %s",name,error);}elseif(!strcmp(args[0],"unload")){error=module_unload(name,TRUE,force);if(error)scr_log_print(LPRINT_LOGNORM,"Module '%s' unloading error: %s",name,error);}elseif(!strcmp(args[0],"info"))module_info_print(name);elsescr_log_print(LPRINT_LOGNORM,"Error: module: Unknown subcommand.");}free_arg_lst(args);#elsescr_log_print(LPRINT_NORMAL,"Please recompile mcabber with modules enabled.");#endif}staticvoiddo_room(char*arg){char**paramlst;char*subcmd;gpointerbud;if(!xmpp_is_online()){scr_LogPrint(LPRINT_NORMAL,"You are not connected.");return;}paramlst=split_arg(arg,2,1);// subcmd, argsubcmd=*paramlst;arg=*(paramlst+1);if(!subcmd||!*subcmd){scr_LogPrint(LPRINT_NORMAL,"Missing parameter.");free_arg_lst(paramlst);return;}if(current_buddy){bud=BUDDATA(current_buddy);}else{if(strcasecmp(subcmd,"join")){free_arg_lst(paramlst);return;}// "room join" is a special case, we don't need to have a valid// current_buddy.bud=NULL;}if(!strcasecmp(subcmd,"join")){if((arg=check_room_subcommand(arg,FALSE,NULL))!=NULL)room_join(bud,arg);}elseif(!strcasecmp(subcmd,"invite")){if((arg=check_room_subcommand(arg,TRUE,bud))!=NULL)room_invite(bud,arg);}elseif(!strcasecmp(subcmd,"affil")){if((arg=check_room_subcommand(arg,TRUE,bud))!=NULL)room_affil(bud,arg);}elseif(!strcasecmp(subcmd,"role")){if((arg=check_room_subcommand(arg,TRUE,bud))!=NULL)room_role(bud,arg);}elseif(!strcasecmp(subcmd,"ban")){if((arg=check_room_subcommand(arg,TRUE,bud))!=NULL)room_ban(bud,arg);}elseif(!strcasecmp(subcmd,"unban")){if((arg=check_room_subcommand(arg,TRUE,bud))!=NULL)room_unban(bud,arg);}elseif(!strcasecmp(subcmd,"kick")){if((arg=check_room_subcommand(arg,TRUE,bud))!=NULL)room_kick(bud,arg);}elseif(!strcasecmp(subcmd,"leave")){if((arg=check_room_subcommand(arg,FALSE,bud))!=NULL)cmd_room_leave(bud,arg);}elseif(!strcasecmp(subcmd,"names")){if((arg=check_room_subcommand(arg,FALSE,bud))!=NULL)room_names(bud,arg);}elseif(!strcasecmp(subcmd,"nick")){if((arg=check_room_subcommand(arg,FALSE,bud))!=NULL)room_nick(bud,arg);}elseif(!strcasecmp(subcmd,"privmsg")){if((arg=check_room_subcommand(arg,TRUE,bud))!=NULL)room_privmsg(bud,arg);}elseif(!strcasecmp(subcmd,"remove")){if((arg=check_room_subcommand(arg,FALSE,bud))!=NULL)room_remove(bud,arg);}elseif(!strcasecmp(subcmd,"destroy")){if((arg=check_room_subcommand(arg,FALSE,bud))!=NULL)room_destroy(bud,arg);}elseif(!strcasecmp(subcmd,"unlock")){if((arg=check_room_subcommand(arg,FALSE,bud))!=NULL)room_unlock(bud,arg);}elseif(!strcasecmp(subcmd,"setopt")){if((arg=check_room_subcommand(arg,FALSE,bud))!=NULL)room_setopt(bud,arg);}elseif(!strcasecmp(subcmd,"topic")){if((arg=check_room_subcommand(arg,FALSE,bud))!=NULL)room_topic(bud,arg);}elseif(!strcasecmp(subcmd,"whois")){if((arg=check_room_subcommand(arg,TRUE,bud))!=NULL)cmd_room_whois(bud,arg,TRUE);}elseif(!strcasecmp(subcmd,"bookmark")){if(!arg&&!buddy_getjid(BUDDATA(current_buddy))&&buddy_gettype(BUDDATA(current_buddy))==ROSTER_TYPE_SPECIAL)display_all_bookmarks();elseif((arg=check_room_subcommand(arg,FALSE,bud))!=NULL)room_bookmark(bud,arg);}else{scr_LogPrint(LPRINT_NORMAL,"Unrecognized parameter!");}free_arg_lst(paramlst);}staticvoiddo_authorization(char*arg){char**paramlst;char*subcmd;char*jid_utf8;if(!xmpp_is_online()){scr_LogPrint(LPRINT_NORMAL,"You are not connected.");return;}paramlst=split_arg(arg,2,0);// subcmd, [jid]subcmd=*paramlst;arg=*(paramlst+1);if(!subcmd||!*subcmd){scr_LogPrint(LPRINT_NORMAL,"Missing parameter.");gotodo_authorization_return;}// Use the provided jid, if it looks validif(arg){if(!*arg){// If no jid is provided, we use the current selected buddyarg=NULL;}else{if(check_jid_syntax(arg)){scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"<%s> is not a valid Jabber ID.",arg);gotodo_authorization_return;}}}if(!arg){// Use the current selected buddy's jidgpointerbud;guinttype;if(!current_buddy)gotodo_authorization_return;bud=BUDDATA(current_buddy);jid_utf8=arg=(char*)buddy_getjid(bud);type=buddy_gettype(bud);if(!(type&(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT))){scr_LogPrint(LPRINT_NORMAL,"Invalid buddy.");gotodo_authorization_return;}}else{jid_utf8=to_utf8(arg);}if(!strcasecmp(subcmd,"allow")){xmpp_send_s10n(jid_utf8,LM_MESSAGE_SUB_TYPE_SUBSCRIBED);scr_LogPrint(LPRINT_LOGNORM,"Sent presence subscription approval to <%s>.",jid_utf8);}elseif(!strcasecmp(subcmd,"cancel")){xmpp_send_s10n(jid_utf8,LM_MESSAGE_SUB_TYPE_UNSUBSCRIBED);scr_LogPrint(LPRINT_LOGNORM,"<%s> will no longer receive your presence updates.",jid_utf8);}elseif(!strcasecmp(subcmd,"request")){xmpp_send_s10n(jid_utf8,LM_MESSAGE_SUB_TYPE_SUBSCRIBE);scr_LogPrint(LPRINT_LOGNORM,"Sent presence notification request to <%s>.",jid_utf8);}elseif(!strcasecmp(subcmd,"request_unsubscribe")){xmpp_send_s10n(jid_utf8,LM_MESSAGE_SUB_TYPE_UNSUBSCRIBE);scr_LogPrint(LPRINT_LOGNORM,"Sent presence notification unsubscription request to <%s>.",jid_utf8);}else{scr_LogPrint(LPRINT_NORMAL,"Unrecognized parameter!");}// Only free jid_utf8 if it has been allocated, i.e. if != arg.if(jid_utf8&&jid_utf8!=arg)g_free(jid_utf8);do_authorization_return:free_arg_lst(paramlst);}staticvoiddo_version(char*arg){gchar*ver=mcabber_version();scr_LogPrint(LPRINT_NORMAL,"This is mcabber version %s.",ver);g_free(ver);#ifdef MODULES_ENABLEscr_LogPrint(LPRINT_NORMAL,"Compiled with modules support (API %s:%d-%d).",MCABBER_BRANCH,MCABBER_API_MIN,MCABBER_API_VERSION);# ifdef PKGLIB_DIRscr_LogPrint(LPRINT_NORMAL," Modules directory: "PKGLIB_DIR);# endif#endif}staticvoiddo_request(char*arg){char**paramlst;char*fjid,*type;enumiqreq_typenumtype=iqreq_none;char*jid_utf8=NULL;paramlst=split_arg(arg,2,0);// type, jidtype=*paramlst;fjid=*(paramlst+1);if(type){// Quick check...if(!strcasecmp(type,"version"))numtype=iqreq_version;elseif(!strcasecmp(type,"time"))numtype=iqreq_time;elseif(!strcasecmp(type,"last"))numtype=iqreq_last;elseif(!strcasecmp(type,"ping"))numtype=iqreq_ping;elseif(!strcasecmp(type,"vcard"))numtype=iqreq_vcard;}if(!type||!numtype){scr_LogPrint(LPRINT_NORMAL,"Please specify a query type (version, time...).");free_arg_lst(paramlst);return;}if(!xmpp_is_online()){scr_LogPrint(LPRINT_NORMAL,"You are not connected.");free_arg_lst(paramlst);return;}// Allow special jid "" or "." (current buddy)if(fjid&&(!*fjid||!strcmp(fjid,".")))fjid=NULL;if(fjid){// The JID has been specified. Quick check...if(check_jid_syntax(fjid)){scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"<%s> is not a valid Jabber ID.",fjid);fjid=NULL;}else{// Convert jid to lowercasechar*p;for(p=fjid;*p&&*p!=JID_RESOURCE_SEPARATOR;p++)*p=tolower(*p);fjid=jid_utf8=to_utf8(fjid);}}else{// Add the current buddyif(current_buddy)fjid=(char*)buddy_getjid(BUDDATA(current_buddy));if(!fjid)scr_LogPrint(LPRINT_NORMAL,"Please specify a Jabber ID.");}if(fjid){switch(numtype){caseiqreq_vcard:{// vCards requests are sent to the bare jid, except in MUC roomsgchar*tmp=strchr(fjid,JID_RESOURCE_SEPARATOR);if(tmp){gchar*bjid=jidtodisp(fjid);if(!roster_find(bjid,jidsearch,ROSTER_TYPE_ROOM))*tmp='\0';g_free(bjid);}}caseiqreq_version:caseiqreq_time:caseiqreq_last:caseiqreq_ping:xmpp_request(fjid,numtype);break;default:break;}}g_free(jid_utf8);free_arg_lst(paramlst);}staticvoiddo_event(char*arg){char**paramlst;char*evid,*subcmd;intaction=-1;paramlst=split_arg(arg,3,1);// id, subcmd, optional argevid=*paramlst;subcmd=*(paramlst+1);if(!evid||!subcmd){// Special case: /event listif(evid&&!strcasecmp(evid,"list"))evs_display_list();elsescr_LogPrint(LPRINT_NORMAL,"Missing parameter. Usage: /event num action ""[event-specific args]");free_arg_lst(paramlst);return;}if(!strcasecmp(subcmd,"reject"))action=EVS_CONTEXT_REJECT;elseif(!strcasecmp(subcmd,"accept"))action=EVS_CONTEXT_ACCEPT;elseif(!strcasecmp(subcmd,"ignore"))action=EVS_CONTEXT_CANCEL;if(action==-1){scr_LogPrint(LPRINT_NORMAL,"Wrong action parameter.");}else{GSList*p;GSList*evidlst;if(!strcmp(evid,"*")){// Use completion listevidlst=evs_geteventslist();}else{// Let's create a slist with the provided event idevidlst=g_slist_append(NULL,evid);}for(p=evidlst;p;p=g_slist_next(p)){if(evs_callback(p->data,action,(constchar*)*(paramlst+2))==-1){scr_LogPrint(LPRINT_NORMAL,"Event %s not found.",(constchar*)p->data);}}g_slist_free(evidlst);}free_arg_lst(paramlst);}staticvoiddo_pgp(char*arg){char**paramlst;char*fjid,*subcmd,*keyid;enum{pgp_none,pgp_enable,pgp_disable,pgp_setkey,pgp_force,pgp_info}op=0;intforce=FALSE;paramlst=split_arg(arg,3,0);// subcmd, jid, [key]subcmd=*paramlst;fjid=*(paramlst+1);keyid=*(paramlst+2);if(!subcmd)fjid=NULL;if(!fjid)keyid=NULL;if(subcmd){if(!strcasecmp(subcmd,"enable"))op=pgp_enable;elseif(!strcasecmp(subcmd,"disable"))op=pgp_disable;elseif(!strcasecmp(subcmd,"setkey"))op=pgp_setkey;elseif((!strcasecmp(subcmd,"force"))||(!strcasecmp(subcmd,"+force"))){op=pgp_force;force=TRUE;}elseif(!strcasecmp(subcmd,"-force"))op=pgp_force;elseif(!strcasecmp(subcmd,"info"))op=pgp_info;}if(!op){scr_LogPrint(LPRINT_NORMAL,"Unrecognized or missing parameter!");free_arg_lst(paramlst);return;}// Allow special jid "" or "." (current buddy)if(fjid&&(!*fjid||!strcmp(fjid,".")))fjid=NULL;if(fjid){// The JID has been specified. Quick check...if(check_jid_syntax(fjid)||!strchr(fjid,'@')){scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"<%s> is not a valid Jabber ID.",fjid);fjid=NULL;}else{// Convert jid to lowercase and strip resourcechar*p;for(p=fjid;*p&&*p!=JID_RESOURCE_SEPARATOR;p++)*p=tolower(*p);if(*p==JID_RESOURCE_SEPARATOR)*p='\0';}}else{gpointerbud=NULL;if(current_buddy)bud=BUDDATA(current_buddy);if(bud){guinttype=buddy_gettype(bud);if(type&ROSTER_TYPE_USER)// Is it a user?fjid=(char*)buddy_getjid(bud);elsescr_LogPrint(LPRINT_NORMAL,"The selected item should be a user.");}}if(fjid){// fjid is actually a bare jid...guintdisabled;GString*sbuf;switch(op){casepgp_enable:casepgp_disable:settings_pgp_setdisabled(fjid,(op==pgp_disable?TRUE:FALSE));break;casepgp_force:settings_pgp_setforce(fjid,force);break;casepgp_setkey:settings_pgp_setkeyid(fjid,keyid);break;casepgp_info:sbuf=g_string_new("");if(settings_pgp_getkeyid(fjid)){g_string_printf(sbuf,"PGP Encryption key id: %s",settings_pgp_getkeyid(fjid));scr_WriteIncomingMessage(fjid,sbuf->str,0,HBB_PREFIX_INFO,0);}disabled=settings_pgp_getdisabled(fjid);g_string_printf(sbuf,"PGP encryption is %s",(disabled?"disabled":"enabled"));scr_WriteIncomingMessage(fjid,sbuf->str,0,HBB_PREFIX_INFO,0);if(!disabled&&settings_pgp_getforce(fjid)){scr_WriteIncomingMessage(fjid,"Encryption enforced (no negotiation)",0,HBB_PREFIX_INFO,0);}g_string_free(sbuf,TRUE);break;default:break;}}else{scr_LogPrint(LPRINT_NORMAL,"Please specify a valid Jabber ID.");}free_arg_lst(paramlst);}staticvoiddo_otr(char*arg){#ifdef HAVE_LIBOTRchar**paramlst;char*fjid,*subcmd,*keyid;enum{otr_none,otr_start,otr_stop,otr_fpr,otr_smpq,otr_smpr,otr_smpa,otr_k,otr_info}op=0;if(!otr_enabled()){scr_LogPrint(LPRINT_LOGNORM,"Warning: OTR hasn't been enabled -- command ignored.");return;}paramlst=split_arg(arg,3,0);// subcmd, jid, [key]subcmd=*paramlst;fjid=*(paramlst+1);keyid=*(paramlst+2);if(!subcmd)fjid=NULL;if(!fjid)keyid=NULL;if(subcmd){if(!strcasecmp(subcmd,"start"))op=otr_start;elseif(!strcasecmp(subcmd,"stop"))op=otr_stop;elseif(!strcasecmp(subcmd,"fingerprint"))op=otr_fpr;elseif(!strcasecmp(subcmd,"smpq"))op=otr_smpq;elseif(!strcasecmp(subcmd,"smpr"))op=otr_smpr;elseif(!strcasecmp(subcmd,"smpa"))op=otr_smpa;elseif(!strcasecmp(subcmd,"key"))op=otr_k;elseif(!strcasecmp(subcmd,"info"))op=otr_info;}if(!op){scr_LogPrint(LPRINT_NORMAL,"Unrecognized or missing parameter!");free_arg_lst(paramlst);return;}if(op==otr_k){otr_key();}else{// Allow special jid "" or "." (current buddy)if(fjid&&(!*fjid||!strcmp(fjid,".")))fjid=NULL;if(fjid){// The JID has been specified. Quick check...if(check_jid_syntax(fjid)||!strchr(fjid,'@')){scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"<%s> is not a valid Jabber ID.",fjid);fjid=NULL;}else{// Convert jid to lowercase and strip resourcechar*p;for(p=fjid;*p&&*p!=JID_RESOURCE_SEPARATOR;p++)*p=tolower(*p);if(*p==JID_RESOURCE_SEPARATOR)*p='\0';}}else{gpointerbud=NULL;if(current_buddy)bud=BUDDATA(current_buddy);if(bud){guinttype=buddy_gettype(bud);if(type&ROSTER_TYPE_USER)// Is it a user?fjid=(char*)buddy_getjid(bud);elsescr_LogPrint(LPRINT_NORMAL,"The selected item should be a user.");}}if(fjid){// fjid is actually a bare jid...switch(op){caseotr_start:otr_establish(fjid);break;caseotr_stop:otr_disconnect(fjid);break;caseotr_fpr:otr_fingerprint(fjid,keyid);break;caseotr_smpq:otr_smp_query(fjid,keyid);break;caseotr_smpr:otr_smp_respond(fjid,keyid);break;caseotr_smpa:otr_smp_abort(fjid);break;caseotr_info:otr_print_info(fjid);break;default:break;}}else{scr_LogPrint(LPRINT_NORMAL,"Please specify a valid Jabber ID.");}}free_arg_lst(paramlst);#elsescr_LogPrint(LPRINT_NORMAL,"Please recompile mcabber with libotr enabled.");#endif /* HAVE_LIBOTR */}#ifdef HAVE_LIBOTRstaticchar*string_for_otrpolicy(enumotr_policyp){switch(p){caseplain:return"plain";caseopportunistic:return"opportunistic";casemanual:return"manual";casealways:return"always";default:return"unknown";}}staticvoiddump_otrpolicy(char*k,char*v,void*nothing){scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"otrpolicy for %s: %s",k,string_for_otrpolicy(*(enumotr_policy*)v));}#endifstaticvoiddo_otrpolicy(char*arg){#ifdef HAVE_LIBOTRchar**paramlst;char*fjid,*policy;enumotr_policyp;paramlst=split_arg(arg,2,0);// [jid|default] policyfjid=*paramlst;policy=*(paramlst+1);if(!fjid&&!policy){scr_LogPrint(LPRINT_NORMAL,"default otrpolicy: %s",string_for_otrpolicy(settings_otr_getpolicy(NULL)));settings_foreach(SETTINGS_TYPE_OTR,&dump_otrpolicy,NULL);free_arg_lst(paramlst);return;}if(!policy){scr_LogPrint(LPRINT_NORMAL,"Please call otrpolicy correctly: /otrpolicy (default|jid) ""(plain|manual|opportunistic|always)");free_arg_lst(paramlst);return;}if(!strcasecmp(policy,"plain")){p=plain;}elseif(!strcasecmp(policy,"manual")){p=manual;}elseif(!strcasecmp(policy,"opportunistic")){p=opportunistic;}elseif(!strcasecmp(policy,"always")){p=always;}else{/* Fail, we don't know _this_ policy*/scr_LogPrint(LPRINT_NORMAL,"mcabber doesn't support _this_ policy!");free_arg_lst(paramlst);return;}if(!strcasecmp(fjid,"default")||!strcasecmp(fjid,"*")){/*set default policy*/settings_otr_setpolicy(NULL,p);free_arg_lst(paramlst);return;}// Allow special jid "" or "." (current buddy)if(fjid&&(!*fjid||!strcmp(fjid,".")))fjid=NULL;if(fjid){// The JID has been specified. Quick check...if(check_jid_syntax(fjid)||!strchr(fjid,'@')){scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,"<%s> is not a valid Jabber ID.",fjid);fjid=NULL;}else{// Convert jid to lowercase and strip resourcechar*p;for(p=fjid;*p&&*p!=JID_RESOURCE_SEPARATOR;p++)*p=tolower(*p);if(*p==JID_RESOURCE_SEPARATOR)*p='\0';}}else{gpointerbud=NULL;if(current_buddy)bud=BUDDATA(current_buddy);if(bud){guinttype=buddy_gettype(bud);if(type&ROSTER_TYPE_USER)// Is it a user?fjid=(char*)buddy_getjid(bud);elsescr_LogPrint(LPRINT_NORMAL,"The selected item should be a user.");}}if(fjid)settings_otr_setpolicy(fjid,p);elsescr_LogPrint(LPRINT_NORMAL,"Please specify a valid Jabber ID.");free_arg_lst(paramlst);#elsescr_LogPrint(LPRINT_NORMAL,"Please recompile mcabber with libotr enabled.");#endif /* HAVE_LIBOTR */}/* !!! After changing the /iline arguments names here, you must change ones in init_bindings().*/staticvoiddo_iline(char*arg){if(!strcasecmp(arg,"fword")){readline_forward_word();}elseif(!strcasecmp(arg,"bword")){readline_backward_word();}elseif(!strcasecmp(arg,"word_fdel")){readline_forward_kill_word();}elseif(!strcasecmp(arg,"word_bdel")){readline_backward_kill_word();}elseif(!strcasecmp(arg,"word_upcase")){readline_updowncase_word(1);}elseif(!strcasecmp(arg,"word_downcase")){readline_updowncase_word(0);}elseif(!strcasecmp(arg,"word_capit")){readline_capitalize_word();}elseif(!strcasecmp(arg,"fchar")){readline_forward_char();}elseif(!strcasecmp(arg,"bchar")){readline_backward_char();}elseif(!strcasecmp(arg,"char_fdel")){readline_forward_kill_char();}elseif(!strcasecmp(arg,"char_bdel")){readline_backward_kill_char();}elseif(!strcasecmp(arg,"char_swap")){readline_transpose_chars();}elseif(!strcasecmp(arg,"hist_beginning_search_bwd")){readline_hist_beginning_search_bwd();}elseif(!strcasecmp(arg,"hist_beginning_search_fwd")){readline_hist_beginning_search_fwd();}elseif(!strcasecmp(arg,"hist_prev")){readline_hist_prev();}elseif(!strcasecmp(arg,"hist_next")){readline_hist_next();}elseif(!strcasecmp(arg,"iline_start")){readline_iline_start();}elseif(!strcasecmp(arg,"iline_end")){readline_iline_end();}elseif(!strcasecmp(arg,"iline_fdel")){readline_forward_kill_iline();}elseif(!strcasecmp(arg,"iline_bdel")){readline_backward_kill_iline();}elseif(!strcasecmp(arg,"send_multiline")){readline_send_multiline();}elseif(!strcasecmp(arg,"iline_accept")){readline_accept_line(FALSE);}elseif(!strcasecmp(arg,"iline_accept_down_hist")){readline_accept_line(TRUE);}elseif(!strcasecmp(arg,"compl_cancel")){readline_cancel_completion();}elseif(!strcasecmp(arg,"compl_do_fwd")){readline_do_completion(TRUE);}elseif(!strcasecmp(arg,"compl_do_bwd")){readline_do_completion(FALSE);}elseif(!strcasecmp(arg,"clear_history")){readline_clear_history();}else{char**paramlst;char*subcmd;paramlst=split_arg(arg,2,0);// subcmd, argsubcmd=*paramlst;arg=*(paramlst+1);if(!subcmd||!*subcmd){scr_LogPrint(LPRINT_NORMAL,"Missing parameter.");free_arg_lst(paramlst);return;}if(!strcasecmp(subcmd,"iline_insert")){readline_insert(arg);}else{scr_LogPrint(LPRINT_NORMAL,"Invalid subcommand.");}free_arg_lst(paramlst);}}staticvoiddo_screen_refresh(char*arg){readline_refresh_screen();}staticvoiddo_chat_disable(char*arg){guintshow_roster;if(arg&&!strcasecmp(arg,"--show-roster"))show_roster=1;elseshow_roster=0;readline_disable_chat_mode(show_roster);}staticintsource_print_error(constchar*path,inteerrno){scr_LogPrint(LPRINT_DEBUG,"Source: glob (%s) error: %s.",path,strerror(eerrno));return0;}staticvoiddo_source(char*arg){staticintrecur_level;gchar*filename,*expfname;glob_tflist;if(!*arg){scr_LogPrint(LPRINT_NORMAL,"Missing filename.");return;}if(recur_level>20){scr_LogPrint(LPRINT_LOGNORM,"** Too many source commands!");return;}filename=g_strdup(arg);strip_arg_special_chars(filename);expfname=expand_filename(filename);g_free(filename);// matchflist.gl_offs=0;if(glob(expfname,0,source_print_error,&flist)){scr_LogPrint(LPRINT_LOGNORM,"Source: error: %s.",strerror(errno));}else{unsignedinti;// sort listfor(i=1;i<flist.gl_pathc;++i){intj;for(j=i-1;j>0;--j){char*a=flist.gl_pathv[j+1];char*b=flist.gl_pathv[j];if(strcmp(a,b)<0){flist.gl_pathv[j]=a;flist.gl_pathv[j+1]=b;}else{break;}}}// source files in listfor(i=0;i<flist.gl_pathc;++i){recur_level++;cfg_read_file(flist.gl_pathv[i],FALSE);recur_level--;}// freeglobfree(&flist);}g_free(expfname);}staticvoiddo_connect(char*arg){xmpp_connect();}staticvoiddo_disconnect(char*arg){xmpp_disconnect();}staticvoiddo_help(char*arg){help_process(arg);}staticvoiddo_echo(char*arg){if(arg)scr_print_logwindow(arg);}staticvoiddo_carbons(char*arg){if(!strcasecmp(arg,"info")||!*arg){carbons_info();}elseif(!strcasecmp(arg,"enable")){carbons_enable();}elseif(!strcasecmp(arg,"disable")){carbons_disable();}else{scr_log_print(LPRINT_NORMAL,"Unrecognized parameter!");}}/* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2: For Vim users... */