//---------------------------------------------------------------------------
// Based on www.xchat.org provided plugin header - works ONLY with new plugin
// system for xchat versions >= 2.x
//
// http://mircryption.sourceforge.net
// By Dark Raichu and Xro, 1/03 ...
// 4/27/03 fixed lines with / not being encrypted
// 4/28/03 added \017 characters to format, which allows nicks to be clicked.
// 5/09/03 changed default keyfile location to ~/.xchat/MircryptionKeys.txt
// 5/13/03 added windows compatibility (tested with xygwin and xchat2 for win32)
// 9/08/03 added support for ` prefix toggle
// 12/27/03 added color stripping [hadez@darklab.org]
// 03/21/04 help message was saying to call '/setkey #chan key' instead of '/setkey key'
// 03/30/04 changed default outgoing tag to +OK for better default compatibility with other scripts
// 05/18/04 added meow support
// 12/26/04 fixing for xchat umlaout bug (utf8 stuff)
// 01/08/04 added new cbc blowfish modes
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// xchat plugin version
#define XMC_VERSIONSTRING "0.1.0xmc"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// cygwin may not have WIN32 defined (which we use AND more imp xchat.h uses)
#ifndef WIN32
#ifdef _MSC_VER
#define WIN32
#endif
#ifdef __CYGWIN__
#define WIN32
#endif
#ifdef __MINGW32__
#define WIN32
#endif
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// default key file name and location
#ifdef WIN32
#define DEFAULTKEYFILE "MircryptionKeys.txt"
#else
// note if no / at front then this is relative filename off of user's home dir
// remember that the . at start of name makes the file visible only w/ ls -a
#define DEFAULTKEYFILE ".MircryptionKeys.txt"
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// xchat function and enum definitions
#include "xchat-plugin.h"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Application includes
#include "mirc_codes.h"
#include "mircryption.h"
#include <stdlib.h>
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Uncomment one of these pairs to choose how encrypted messages are formatted
// Default mircryption method, use [] around encrypted text
#define EMESSAGE_RECV_FORMAT "\00302[\017\00300%s\017\00302]\017\t%s\n"
#define EMESSAGE_SEND_FORMAT "\00306[\017\00300%s\017\00306]\017\t%s\n"
#define ENOTICE_RECV_FORMAT "\00302-[\017\00313%s\017\00302]-\017\t%s\n"
#define ENOTICE_SEND_FORMAT "\00303]\017\00300%s\017\00303[\017\t%s\n"
#define EMSG_SEND_FORMAT ENOTICE_SEND_FORMAT
#define EACTIONFORMAT "[\00313*\017]\t%s %s\n"
// Xro prefers a prefix of mc before <>
//#define EMESSAGEFORMAT "mc \00303>\00300%s\00303<\00300\t%s"
//#define EACTIONFORMAT "mc \00313*\00300\t%s %s"
// house uses the following:
//#define EMESSAGE_SEND_FORMAT "\00306[\017%s\00306]\017\t%s\n"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Here you can choose what outgoing tag to use; the defaul is mcps
// but you can set it to +OK if you want to be compatible with others apps.
// just comment out the one you *dont* want to use with a //
//#define OUTGOINGETAG "mcps"
#define OUTGOINGETAG "+OK"
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// If you want to force your xchat plugin to ignore meow broadcasts, you
// can set this to true. Meows are just fun ways of saying hello to fello
// mircryption users.
#define IGNOREMEOWS false
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// global plugin handle
static xchat_plugin *ph;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// pointer to global mircryptor which does the bulk of the work
MircryptionClass_xchat *mircryptor=NULL;
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Forward declarations
static int setdefault_keyfilelocation();
//
static int mc_event_privdialog(char *word[], void *userdata);
static int mc_event_channelmessage(char *word[], void *userdata);
static int mc_event_action(char *word[], void *userdata);
static int mc_event_channelnotice(char *word[], void *userdata);
static int mc_event_notice(char *word[], void *userdata);
static int mc_event_topic(char *word[], void *userdata);
static int mc_event_topicchange(char *word[], void *userdata);
static int mc_event_yourmessage(char *word[], void *userdata);
static int mc_event_noticesend(char *word[], void *userdata);
//
static int mc_help(char *word[], char *word_eol[], void *userdata);
static int mc_setkey(char *word[], char *word_eol[], void *userdata);
static int mc_delkey(char *word[], char *word_eol[], void *userdata);
static int mc_disablekey(char *word[], char *word_eol[], void *userdata);
static int mc_enablekey(char *word[], char *word_eol[], void *userdata);
static int mc_displaykey(char *word[], char *word_eol[], void *userdata);
static int mc_listkeys(char *word[], char *word_eol[], void *userdata);
static int mc_keypassphrase(char *word[], char *word_eol[], void *userdata);
static int mc_setkeyfile(char *word[], char *word_eol[], void *userdata);
static int mc_etopic(char *word[], char *word_eol[], void *userdata);
static int mc_alltext(char *word[], char *word_eol[], void *userdata);
static int mc_action(char *word[], char *word_eol[], void *userdata);
static int mc_notice(char *word[], char *word_eol[], void *userdata);
static void mylowercasify(char *str);
/*
Author: hadez@darklab.org
Description: see function code at bottom of file for details
*/
void strip_mirc_colors(xchat_plugin*,char*);
// meow handling
bool HandleMeow(char *channelname,char *nick,char *text);
// xchat umlaout issue (utf8 stuff)
void Utf8DirtyFix(char *intext,char *outtext);
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// new extra safe buffer overflow checks
// thanks to www.rainbowcrack-online.com and ircfuz for finding this dangeroud possibility
// more serious buffer overflow checks are also now in the dll as well
void mcnicksafe_strcpy(char *dest,const char*src) {mcsafe_strcpy(dest,src,MAXCHANNELNAMESIZE);};
void mclinesafe_strcpy(char *dest,const char*src) {mcsafe_strcpy(dest,src,MAXLINELEN);};
void mckeysafe_strcpy(char *dest,const char*src) {mcsafe_strcpy(dest,src,MAXSAFEKEYSIZE);};
void mcsafe_strcpy(char *dest,const char *src, int maxlen) {if (strlen(src)<maxlen-1) strcpy(dest,src); else {strncpy(dest,src,maxlen-1);dest[maxlen-1]='\0';};};
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// do we need a dummy main for some compilers
// ATTN: new 07/10/03
// int main(int argc,void **argv) {return 0;}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
extern "C" int xchat_plugin_init(xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
{
// plugin is being loaded
// save this in order to call xchat_* functions
ph = plugin_handle;
// xchat plugin info
*plugin_name = "mircryption";
*plugin_desc = "Mircryption - cryptographic addon for mirc/xchat (http://mircryption.sourceforge.net)";
*plugin_version = XMC_VERSIONSTRING;
// hook the commands we provide
xchat_hook_command(ph, "mircryption", PRI_NORM, mc_help, "Usage: MIRCRYPTION, shows help for mircryption", 0);
xchat_hook_command(ph, "setkey", PRI_NORM, mc_setkey, "Usage: SETKEY keyphrase.., enables encryption/decryption on current channel, using key specified; can be used to add or modify keys.", 0);
xchat_hook_command(ph, "delkey", PRI_NORM, mc_delkey, "Usage: DELKEY, removes encryption key from current channel.", 0);
xchat_hook_command(ph, "disablekey", PRI_NORM, mc_disablekey, "Usage: DISABLEKEY, temporarily disables encryption for current channel", 0);
xchat_hook_command(ph, "enablekey", PRI_NORM, mc_enablekey, "Usage: ENABLEKEY, re-enables encryption for current channel", 0);
xchat_hook_command(ph, "displaykey", PRI_NORM, mc_displaykey, "Usage: DISPLAYKEY, shows you (and only you) the key for the current channel", 0);
xchat_hook_command(ph, "listkeys", PRI_NORM, mc_listkeys, "Usage: LISTKEYS, lists all channel encryption keys currently stored", 0);
xchat_hook_command(ph, "keypassphrase", PRI_NORM, mc_keypassphrase, "", 0); // legacy
xchat_hook_command(ph, "masterkey", PRI_NORM, mc_keypassphrase, "Usage: MASTERKEY phrase.., set or change current master keyfile passphrase to 'phrase'", 0);
xchat_hook_command(ph, "setkeyfile", PRI_NORM, mc_setkeyfile, "Usage: SETKEYFILE filename, set the name of the file to be used for storing/retrieving keys", 0);
xchat_hook_command(ph, "etopic", PRI_NORM, mc_etopic, "Usage: ETOPIC text.., encrypt the topic for the current channel to text", 0);
xchat_hook_command(ph, "me", PRI_NORM, mc_action, "Usage: ME <action>", 0);
xchat_hook_command(ph, "notice", PRI_NORM, mc_notice, "Usage: NOTICE <nick/channel> <message>, sends a notice. Notices are a type of message that should be auto reacted to", 0);
xchat_hook_command(ph, "", PRI_NORM, mc_alltext, "trap all input for encryption", 0);
// hook the events we want to respond to
xchat_hook_print(ph, "Channel Message", PRI_NORM, mc_event_channelmessage, 0);
xchat_hook_print(ph, "Channel Notice", PRI_NORM, mc_event_channelnotice, 0);
xchat_hook_print(ph, "Channel Action", PRI_NORM, mc_event_action, 0);
xchat_hook_print(ph, "Notice", PRI_NORM, mc_event_notice, 0);
xchat_hook_print(ph, "Topic", PRI_NORM, mc_event_topic, 0);
xchat_hook_print(ph, "Topic Change", PRI_NORM, mc_event_topicchange, 0);
xchat_hook_print(ph, "Your Message", PRI_NORM, mc_event_yourmessage, 0);
xchat_hook_print(ph, "Notice Send", PRI_NORM, mc_event_noticesend, 0);
xchat_hook_print(ph, "Private Message to Dialog", PRI_NORM, mc_event_privdialog, 0);
// create our mircryptor class which does the bulk of the work
mircryptor=new MircryptionClass_xchat;
// set keyfile to ~/.MircryptionKeys.txt
setdefault_keyfilelocation();
// if keyfile is not yet unlocked, then unlock them
mircryptor->load_keys();
// inform user that the addon is loaded
xchat_printf(ph, "Mircryption ver %s loaded - encryption currently *disabled*\n",XMC_VERSIONSTRING);
xchat_printf(ph, " type /masterkey PASSPHRASE to activate, or /mircryption for help.\n");
// return 1 for success
return 1;
}
extern "C" int xchat_plugin_deinit (xchat_plugin *plugin_handle)
{
// plugin needs to shut down
// free mircryptor object
if (mircryptor!=NULL)
delete mircryptor;
mircryptor=NULL;
// return 1 for success
return 1;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
static int setdefault_keyfilelocation()
{
// set default key file location
char returndata[MAXRETURNSTRINGLEN];
char keyfile[1000];
// form default keyfile name
strcpy(keyfile,DEFAULTKEYFILE);
#ifndef WIN32
if (keyfile[0]!='/')
{
// we need to grab users home explicitly, using ~/ didnt work
strcpy(keyfile,getenv("HOME"));
if (strlen(keyfile)>0)
strcat(keyfile,"/");
strcat(keyfile,DEFAULTKEYFILE);
}
#endif
mircryptor->mc_setkeyfilename(keyfile,returndata);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
static int mc_event_privdialog(char *word[], void *userdata)
{
// handle event
char returndata[MAXRETURNSTRINGLEN];
bool bretv;
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
channelname[MAXCHANNELNAMESIZE-1]='\0';
// new force lowercase
mylowercasify(channelname);
char nick[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(nick,word[1]);
nick[MAXCHANNELNAMESIZE-1]='\0';
char text[MAXLINELEN];
mclinesafe_strcpy(text,word[2]);
// decrypt it
bretv=mircryptor->mc_decrypt2(channelname,text,returndata);
if (!bretv)
{
if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
xchat_print(ph,returndata);
return EAT_NONE;
}
else if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
{
// it was decrypted so we handle it
//xchat_printf(ph,"[%s] %s",nick,returndata);
//xchat_commandf(ph,"recv :%s!%s@mircryption PRIVMSG %s :(e) %s",nick,nick,channelname,returndata);
strip_mirc_colors(ph,returndata);
//check if it's a fish stype crypted action [hadez]
if(strncmp(returndata,"\001ACTION ",8) == 0)
{
// something smells fishy here
// get rid of the trailing \001
returndata[strlen(returndata)-1] = '\0';
// ignore the "\001ACTION " part and print it in eaction format
xchat_printf(ph,EACTIONFORMAT,nick,returndata+8);
}
else
{
xchat_printf(ph,EMESSAGE_RECV_FORMAT,nick,returndata);
}
//xchat_printf(ph,EMESSAGE_RECV_FORMAT,nick,returndata);
return EAT_ALL;
}
// don't eat this event, let xchat handle it also
return EAT_NONE;
}
static int mc_event_channelmessage(char *word[], void *userdata)
{
// handle event
char returndata[MAXRETURNSTRINGLEN];
bool bretv;
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
char nick[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(nick,word[1]);
char text[MAXLINELEN];
mclinesafe_strcpy(text,word[2]);
// is this a meow?
if (strncmp(text,"mcps meow meow",14)==0)
{
if (HandleMeow(channelname,nick,text))
return EAT_ALL;
}
// decrypt it
bretv=mircryptor->mc_decrypt2(channelname,text,returndata);
if (!bretv)
{
if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
xchat_print(ph,returndata);
return EAT_NONE;
}
else if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
{
// it was decrypted so we handle it
//xchat_printf(ph,"[%s] %s",nick,returndata);
//xchat_commandf(ph,"recv :%s!%s@mircryption PRIVMSG %s :(e) %s",nick,nick,channelname,returndata);
strip_mirc_colors(ph,returndata);
//check if it's a fish stype crypted action [hadez]
if(strncmp(returndata,"\001ACTION ",8) == 0)
{
// something smells fishy here
// get rid of the trailing \001
returndata[strlen(returndata)-1]='\0';
// ignore the "\001ACTION " part and print it in eaction format
xchat_printf(ph,EACTIONFORMAT,nick,returndata+8);
}
else
{
xchat_printf(ph,EMESSAGE_RECV_FORMAT,nick,returndata);
}
//xchat_printf(ph,EMESSAGE_RECV_FORMAT,nick,returndata);
return EAT_ALL;
}
// don't eat this event, let xchat handle it also
return EAT_NONE;
}
static int mc_event_action(char *word[], void *userdata)
{
// handle event
char returndata[MAXRETURNSTRINGLEN];
bool bretv;
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
char nick[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(nick,word[1]);
char text[MAXLINELEN];
mclinesafe_strcpy(text,word[2]);
// decrypt it
bretv=mircryptor->mc_decrypt2(channelname,text,returndata);
if (!bretv)
{
if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
xchat_print(ph,returndata);
return EAT_NONE;
}
else if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
{
// it was decrypted so we handle it
//xchat_printf(ph,"[%s] %s",nick,returndata);
//xchat_commandf(ph,"recv :%s!%s@mircryption PRIVMSG %s :[mc] %s",nick,nick,channelname,returndata);
strip_mirc_colors(ph,returndata);
xchat_printf(ph,EACTIONFORMAT,nick,returndata);
return EAT_ALL;
}
// don't eat this event, let xchat handle it also
return EAT_NONE;
}
static int mc_event_channelnotice(char *word[], void *userdata)
{
// handle event
bool bretv;
char returndata[MAXRETURNSTRINGLEN];
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
char nick[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(nick,word[1]);
char text[MAXLINELEN];
mclinesafe_strcpy(text,word[3]);
// decrypt it
bretv=mircryptor->mc_decrypt2(channelname,text,returndata);
if (!bretv)
{
if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
xchat_print(ph,returndata);
return EAT_NONE;
}
if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
{
// it was decrypted so we handle it
//xchat_printf(ph,"[%s] -> %s",nick,returndata);
//xchat_commandf(ph,"recv :%s!%s@mircryption NOTICE %s :(e) %s",nick,nick,channelname,returndata);
strip_mirc_colors(ph,returndata);
xchat_printf(ph,ENOTICE_RECV_FORMAT,channelname,returndata);
return EAT_ALL;
}
// don't eat this event, let xchat handle it also
return EAT_NONE;
}
static int mc_event_notice(char *word[], void *userdata)
{
// handle event
char returndata[MAXRETURNSTRINGLEN];
bool bretv;
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
char nick[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(nick,word[1]);
char mynick[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(mynick,xchat_get_info(ph, "nick"));
char text[MAXLINELEN];
mclinesafe_strcpy(text,word[2]);
// decrypt it
bretv=mircryptor->mc_decrypt2(channelname,text,returndata);
if (!bretv)
{
if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
xchat_print(ph,returndata);
return EAT_NONE;
}
if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
{
// it was decrypted so we handle it
//xchat_printf(ph,"[%s] -> %s",nick,returndata);
//xchat_commandf(ph,"recv :%s!%s@mircryption NOTICE %s :(e) %s",nick,nick,mynick,returndata);
strip_mirc_colors(ph,returndata);
xchat_printf(ph,ENOTICE_RECV_FORMAT,nick,returndata);
return EAT_ALL;
}
// don't eat this event, let xchat handle it also
return EAT_NONE;
}
static int mc_event_topic(char *word[], void *userdata)
{
// handle event
char returndata[MAXRETURNSTRINGLEN];
bool bretv;
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,word[1]);
// new force lowercase
mylowercasify(channelname);
char text[MAXLINELEN];
mclinesafe_strcpy(text,word[2]);
char mynick[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(mynick,xchat_get_info(ph, "nick"));
char server[255];
mcsafe_strcpy(server,xchat_get_info(ph, "server"),255);
// decrypt it
bretv=mircryptor->mc_decrypt2(channelname,text,returndata);
if (!bretv)
{
if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
xchat_print(ph,returndata);
return EAT_NONE;
}
if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
{
// it was decrypted so we handle it
// we dont need to print it since it will be displayed automatically
// xchat_printf(ph,"Topic for %s is decrypted as: %s",channelname,returndata);
strip_mirc_colors(ph,returndata);
xchat_commandf(ph,"recv :%s 332 %s %s :(e) %s",server,mynick,channelname,returndata);
return EAT_ALL;
}
// don't eat this event, let xchat handle it also
return EAT_NONE;
}
static int mc_event_topicchange(char *word[], void *userdata)
{
// handle event
char returndata[MAXRETURNSTRINGLEN];
bool bretv;
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
char nick[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(nick,word[1]);
char text[MAXLINELEN];
mclinesafe_strcpy(text,word[2]);
// decrypt it
bretv=mircryptor->mc_decrypt2(channelname,text,returndata);
if (!bretv)
{
if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
xchat_print(ph,returndata);
return EAT_NONE;
}
if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
{
// it was decrypted so we handle it
// no need to annnounce it, it will get announced automatically by xchat
// xchat_printf(ph,"%s has encrypted the topic for %s to: %s",nick,channelname,returndata);
strip_mirc_colors(ph,returndata);
xchat_commandf(ph,"recv :%s!%s@mircryption TOPIC %s :(e) %s",nick,nick,channelname,returndata);
return EAT_ALL;
}
//xchat_printf(ph,"TOPICCHANGE nick='%s' chjannel='%s' text='%s' return='%s'",nick,channelname,text,returndata);
// don't eat this event, let xchat handle it also
return EAT_NONE;
}
static int mc_event_yourmessage(char *word[], void *userdata)
{
// issue a command to xchat
// this is kind of wierd because SOMETIMES encryption is handled prior to this in mc_alltext()
char returndata[MAXRETURNSTRINGLEN];
bool bretv;
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
char nick[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(nick,word[1]);
char text[MAXLINELEN];
mclinesafe_strcpy(text,word[2]);
if (strncmp(text,"mcps ",5)==0)
return EAT_ALL;
if (strncmp(text,OUTGOINGETAG,strlen(OUTGOINGETAG))==0)
return EAT_ALL;
// don't eat this event, let xchat handle it also
return EAT_NONE;
}
static int mc_event_noticesend(char *word[], void *userdata)
{
char returndata[MAXRETURNSTRINGLEN];
bool bretv;
// get info
char dest[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(dest,word[1]);
char text[MAXLINELEN];
mclinesafe_strcpy(text,word[2]);
// if its a meow reply then its already displayed by us so we do nothing here
if (strncmp(text,"mcps meow meowreply",19)==0)
return EAT_ALL;
//lets see if we can decrypt the notice we just sent
bretv=mircryptor->mc_decrypt2(dest,text,returndata);
if (!bretv)
{
if (strcmp(returndata,"")!=0)
{
xchat_print(ph,returndata);
return EAT_ALL;
}
else
return EAT_NONE;
}
else if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
{
xchat_printf(ph,ENOTICE_SEND_FORMAT,dest,returndata);
return EAT_ALL;
}
// don't eat this event, let xchat handle it also
return EAT_NONE;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
static int mc_help(char *word[], char *word_eol[], void *userdata)
{
xchat_print(ph,"-\n");
xchat_print(ph,". Mircryption - xchat version - Dark Raichu & Xro\n");
xchat_print(ph,". blowfish encryption algorithms are by bruce schneier and jim conger.\n");
xchat_print(ph,".... /setkey [keyphrase]' enables encryption/decryption on specified channel (defaults to current channel), using key specified. can be used to add or modify keys.\n");
xchat_print(ph,".... /delkey [channel]' removes encryption key for specified channel (defaults to current channel).\n");
xchat_print(ph,".... /disablekey' temporarily disables encryption for current channel\n");
xchat_print(ph,".... /enablekey' re-enables encryption for current channel\n");
xchat_print(ph,".... /displaykey' shows you (and only you) the key for the current channel\n");
// xchat_print(ph,".... /plain ...' send ... text without encryption\n");
xchat_print(ph,".... /listkeys' lists all channel encryption keys currently stored\n");
xchat_print(ph,"... /keypassphrase [phrase]' set or change current master keyfile passphrase to keyword\n");
// xchat_print(ph,".... /mcscheme X' set color/identification scheme, where X is the number 1-3\n");
xchat_print(ph,".... /etopic [text]' set an encrypted topic for the channel.\n");
// xchat_print(ph,".... /encryptecho channelname text' echoes encrypted version of text IF channel is set to encrypt, otherwise plaintext\n");
// xchat_print(ph,".... /decryptecho channelname text' echoes decrypted version of text IF channel has a key, otherwise plaintext\n");
xchat_print(ph,".... /setkeyfile filename' set the name of the file to be used for storing/retrieving keys\n");
// xchat_print(ph,".... /emsg channelname test... replacement for /msg - encrypts text if appropriate (good for bots, etc.)\n");
// xchat_print(ph,".... /mcmeow [channelname] broadcast handshake query to channel\n");
// xchat_print(ph,".... /etext text... same as typing text... in encrypted channel, BUT igores disabling, and wont send to channel without encryption\n");
// xchat_print(ph,".... /textpad launches the textpad dialog for copy and paste of big text\n");
xchat_print(ph,"-\n");
/// eat this command so xchat and other plugins can't process it
return EAT_ALL;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
static int mc_setkey(char *word[], char *word_eol[], void *userdata)
{
// handle this command
char returndata[MAXRETURNSTRINGLEN];
// get info
char keyphrase[MAXKEYSIZE];
mckeysafe_strcpy(keyphrase,word_eol[2]);
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
// execute command
mircryptor->mc_setkey(channelname,keyphrase,returndata);
// display result
xchat_printf(ph, "%s",returndata);
/// eat this command so xchat and other plugins can't process it
return EAT_ALL;
}
static int mc_delkey(char *word[], char *word_eol[], void *userdata)
{
// handle this command
char returndata[MAXRETURNSTRINGLEN];
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
// execute command
mircryptor->mc_delkey(channelname,returndata);
// display result
xchat_printf(ph, "%s",returndata);
/// eat this command so xchat and other plugins can't process it
return EAT_ALL;
}
static int mc_disablekey(char *word[], char *word_eol[], void *userdata)
{
// handle this command
char returndata[MAXRETURNSTRINGLEN];
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
// execute command
mircryptor->mc_disablekey(channelname,returndata);
// display result
xchat_printf(ph, "%s",returndata);
/// eat this command so xchat and other plugins can't process it
return EAT_ALL;
}
static int mc_enablekey(char *word[], char *word_eol[], void *userdata)
{
// handle this command
char returndata[MAXRETURNSTRINGLEN];
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
// execute command
mircryptor->mc_enablekey(channelname,returndata);
// display result
xchat_printf(ph, "%s",returndata);
/// eat this command so xchat and other plugins can't process it
return EAT_ALL;
}
static int mc_displaykey(char *word[], char *word_eol[], void *userdata)
{
// handle this command
char returndata[MAXRETURNSTRINGLEN];
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
// execute command
mircryptor->mc_displaykey(channelname,returndata);
// display result
xchat_printf(ph, "%s",returndata);
/// eat this command so xchat and other plugins can't process it
return EAT_ALL;
}
static int mc_listkeys(char *word[], char *word_eol[], void *userdata)
{
// handle this command
char returndata[MAXRETURNSTRINGLEN];
// execute command
mircryptor->mc_listkeys(returndata);
/// eat this command so xchat and other plugins can't process it
return EAT_ALL;
}
static int mc_keypassphrase(char *word[], char *word_eol[], void *userdata)
{
// handle this command
char returndata[MAXRETURNSTRINGLEN];
// get info
char keyphrase[MAXKEYSIZE];
strcpy(keyphrase,word_eol[2]);
// execute command
mircryptor->mc_setunlockpassphrase(keyphrase,returndata);
// display result
xchat_printf(ph, "%s",returndata);
/// eat this command so xchat and other plugins can't process it
return EAT_ALL;
}
static int mc_setkeyfile(char *word[], char *word_eol[], void *userdata)
{
// handle this command
char returndata[MAXRETURNSTRINGLEN];
// get info
char keyfile[MAXKEYSIZE];
strcpy(keyfile,word_eol[2]);
// execute command
mircryptor->mc_setkeyfilename(keyfile,returndata);
// display result
xchat_printf(ph, "%s",returndata);
/// eat this command so xchat and other plugins can't process it
return EAT_ALL;
}
static int mc_etopic(char *word[], char *word_eol[], void *userdata)
{
// handle this command
bool bretv;
char returndata[MAXRETURNSTRINGLEN];
// get info
char text[MAXLINELEN];
char text2[MAXLINELEN];
strcpy(text,word_eol[2]);
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
// utf8 fix for text
Utf8DirtyFix(text,text2);
// encrypt it
bretv=mircryptor->mc_encrypt2(channelname,text2,returndata);
// xchat_printf(ph,"debug: topic for %s:tried to encrypt '%s' to '%s'",channelname,text,returndata);
if (!bretv)
{
if (strcmp(returndata,"")!=0)
{
xchat_print(ph,returndata);
return EAT_ALL;
}
else
return EAT_NONE;
}
else if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
{
// it was encrypted so we handle it
// send the encrypted text
xchat_commandf(ph,"TOPIC %s %s",channelname,returndata);
// we dont actually display it here, as it will be displayed on the event we trigger when we set the topic
// xchat_printf(ph,"Encrypted topic for [%s] set to: %s",channelname,text);
return EAT_ALL;
}
else
{
// error
xchat_printf(ph,"topic could not be encrypted, so it wasnt set.");
}
/// eat this command so xchat and other plugins can't process it
return EAT_ALL;
}
static int mc_alltext(char *word[], char *word_eol[], void *userdata)
{
// handle this command
bool bretv;
char returndata[MAXRETURNSTRINGLEN];
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
char text[MAXLINELEN];
char text2[MAXLINELEN];
mclinesafe_strcpy(text,word_eol[1]);
char nick[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(nick,xchat_get_info(ph, "nick"));
// note we dont need this (in fact it causes problems) because xchat, unlike mirc
// will not invoke mc_alltext on commands
/*
if (word_eol[1][0]=='/')
{
// a command, so not for us
return EAT_NONE;
}
*/
// are they using the reverse-encryption prefix?
bool isencrypting=mircryptor->mc_isencrypting(channelname,returndata);
if (text[0]=='`')
{
// yes they are using the prefix. remove it.
strcpy(text,&text[1]);
if (isencrypting)
{
// they are normally set to encrypt, so we disable it and send plain text
xchat_commandf(ph,"MSG %s %s",channelname,text);
// we dont show the user what they typed here, it will be shown in event_ourmessage
// xchat_printf(ph,MESSAGE_SEND_FORMAT,nick,text);
return EAT_ALL;
}
// encryption is disabled normally (or doesnt exist at all)
// we just drop through in this case.
}
else if (!isencrypting)
return EAT_NONE;
// utf8 fix for text
Utf8DirtyFix(text,text2);
// encrypt it
bretv=mircryptor->mc_forceencrypt(channelname,text2,returndata);
if (!bretv)
{
if (strcmp(returndata,"")!=0)
{
xchat_print(ph,returndata);
return EAT_ALL;
}
else
return EAT_NONE;
}
else if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
{
// it was encrypted so we handle it
// send the encrypted text
xchat_commandf(ph,"MSG %s %s %s",channelname,OUTGOINGETAG,returndata);
// show user their own text
//xchat_printf(ph,"[%s] %s",nick,text);
//xchat_commandf(ph,"recv :%s!%s@mircryption PRIVMSG %s :(e) %s",nick,nick,channelname,text);
xchat_printf(ph,EMESSAGE_SEND_FORMAT,nick,text);
return EAT_ALL;
}
// let xchat handle this normally
return EAT_NONE;
}
static int mc_action(char *word[], char *word_eol[], void *userdata)
{
// handle this command
bool bretv;
char returndata[MAXRETURNSTRINGLEN];
// get info
char text[MAXLINELEN];
char text2[MAXLINELEN];
strcpy(text,word_eol[2]);
// get info
char channelname[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(channelname,xchat_get_info(ph, "channel"));
// new force lowercase
mylowercasify(channelname);
char nick[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(nick,xchat_get_info(ph, "nick"));
if (strcmp(word[2],"mcps")==0 || strcmp(word[2],OUTGOINGETAG)==0)
{
//we already encrypted it
//even though this is a not-nice hack
//it is necessary to avoid recursive calls
return EAT_NONE;
}
// utf8 fix for text
Utf8DirtyFix(text,text2);
// encrypt it
bretv=mircryptor->mc_encrypt(channelname,text2,returndata);
if (!bretv)
{
if (strcmp(returndata,"")!=0)
{
xchat_print(ph,returndata);
return EAT_ALL;
}
else
return EAT_NONE;
}
else if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
{
// it was encrypted so we handle it
// send the encrypted text
xchat_commandf(ph,"me %s %s",OUTGOINGETAG,returndata);
//xchat_printf(ph,"mc \00313*\00300\t%s %s",nick,text); //xchat already does that when the action comes back from the server
return EAT_ALL;
}
else
{
// error
xchat_printf(ph,"action could not be encrypted, so it wasnt set.");
}
/// eat this command so xchat and other plugins can't process it
return EAT_ALL;
}
static int mc_notice(char *word[], char *word_eol[], void *userdata)
{
// handle this command
bool bretv;
char returndata[MAXRETURNSTRINGLEN];
// get info
char text[MAXLINELEN];
char text2[MAXLINELEN];
mclinesafe_strcpy(text,word_eol[3]);
// get destination (nick/channel)
char dest[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(dest,word[2]);
// new force lowercase
mylowercasify(dest);
if (strcmp(word[3],"mcps")==0 || strcmp(word[3],OUTGOINGETAG)==0)
{
//we already encrypted it
//even though this is a not-nice hack
//it is necessary to avoid recursive calls
return EAT_NONE;
}
// utf8 fix for text
Utf8DirtyFix(text,text2);
// encrypt it
bretv=mircryptor->mc_encrypt(dest,text2,returndata);
if (!bretv)
{
if (strcmp(returndata,"")!=0)
{
xchat_print(ph,returndata);
return EAT_ALL;
}
else
return EAT_NONE;
}
else if (strcmp(returndata,text)!=0 && returndata[0]!='\0')
{
// it was encrypted so we handle it
// send the encrypted text
xchat_commandf(ph,"notice %s %s %s",dest,OUTGOINGETAG,returndata);
//xchat_printf(ph,"mc \00313*\00300\t%s %s",nick,text); //xchat already does that when the action comes back from the server
return EAT_ALL;
}
else
{
// error
xchat_printf(ph,"notice could not be encrypted, so it wasnt sent.");
}
/// eat this command so xchat and other plugins can't process it
return EAT_ALL;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
char *MircryptionClass_xchat::get_classversionstring()
{
// return some version information - you dont have to override this one
return "Mircryption class for xchat";
}
bool MircryptionClass_xchat::present_messsagebox(char *messagetext,char *windowtitle)
{
// present some info to the user, preferably in a pop-up modal dialog
// returns true on success
display_statustext(messagetext);
return false;
}
// we need the user to give us a valid master passphrase
bool MircryptionClass_xchat::request_unlockpassphrase()
{
// return true if user gives us a valid passphrase, and unlock the keys, false if not
// I dont know how to ask xchat client for info yet, so instead we just return false and expect uuser to set it with /keypassphrase
return false;
}
bool MircryptionClass_xchat::send_irccommand(char *irccommand,char *text)
{
// send an irc command to server
// returns true on success
xchat_commandf(ph,"%s %s",irccommand,text);
return false;
}
bool MircryptionClass_xchat::display_statustext(char *messagetext)
{
// display some information for the user in some default text area (like status window in mirc)
// returns true on success
xchat_print(ph, messagetext);
return true;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void mylowercasify(char *str)
{
if (str==NULL)
return;
int len=strlen(str);
char c;
for (int count=0;count<len;++count)
{
c=str[count];
if (c>='A' && c<='Z')
str[count]=c+32;
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
/*
Author: hadez@darklab.org
Date: 27.12.03 22:09
Description: frontend to mirc_codes.h
*/
void strip_mirc_colors(xchat_plugin* ph, char* textline)
{
int i;
const char *str;
if (xchat_get_prefs(ph,"text_stripcolor",&str, &i) == 3) // successfully got boolan value
{
if(i == 1) // stripping enabled
{
mirc_codes::clean(textline);
}
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
bool HandleMeow(char *channelname,char *nick,char *text)
{
// handle a meow and return true on success
char returndata[MAXRETURNSTRINGLEN],estatus[MAXRETURNSTRINGLEN];
bool bretv;
// grab sender string
char *senderstring,*inteststring;
senderstring=strtok(text," ");
senderstring=strtok(NULL," "); senderstring=strtok(NULL," "); senderstring=strtok(NULL," ");senderstring=strtok(NULL," ");
inteststring=strtok(NULL," ");
// if they want to ignore meows
if (IGNOREMEOWS || senderstring==NULL || inteststring==NULL)
{
xchat_printf(ph,"ignoring meow broadcast from %s on channel %s (set IGNOREMEOWS to false in mircryption.cpp to stop ignoring).",nick,channelname);
return true;
}
// decrypt the test string
char teststring[MAXRETURNSTRINGLEN];
sprintf(teststring,"mcps %s",inteststring);
bretv=mircryptor->mc_decrypt2(channelname,teststring,returndata);
if (!bretv || strcmp(returndata,teststring)==0 || returndata[0]=='\0')
{
// no key for chan
strcpy(estatus,"no encryption key for this channel");
}
else
{
// does it match meow senders key
if (strcmp(returndata,"meow")==0)
strcpy(estatus,"crypting (key match)");
else
strcpy(estatus,"crypting (key mismatch)");
}
// get our nick
char mynick[MAXCHANNELNAMESIZE];
mcnicksafe_strcpy(mynick,xchat_get_info(ph, "nick"));
// show user what we are replying
xchat_printf(ph,"[=^.^=] [%s] %s -> meow %s %s",senderstring,nick,channelname,estatus);
// send reply as notice
sprintf(returndata,"mcps meow meowreply %s %s [%s] %s -> %s",nick,channelname,XMC_VERSIONSTRING,mynick,estatus);
xchat_commandf(ph,"notice %s %s",nick,returndata);
// return success
return true;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void Utf8DirtyFix(char *intext,char *outtext)
{
// walk through the string and change any xchat encoded utf8 (glib) special characters
// really the ideal way to fix this is for xchat developers to expose a function to conver the plugin-passed utf8 text to local text
// but for now we use this quick fix
unsigned char c,c2;
int len=strlen(intext);
int desti=0;
for (int count=0;count<len;++count)
{
c=intext[count];
if (c==195)
{
// ok special two-byte character prefix (skip over it)
++count;
c2=intext[count];
// now set c to actual character to replace
if (c2==0)
c=0;
else
{
// apparent dirty fix for utf8
c=c2+64;
}
}
// write it and increment index
outtext[desti]=c;
++desti;
}
// '\0' terminate
outtext[desti]='\0';
}
//---------------------------------------------------------------------------
syntax highlighted by Code2HTML, v. 0.9.1