/**********************************************************************
* PTlink IRC Services is (C) CopyRight PTlink IRC Software 1999-2006 *
* http://software.pt-link.net *
* This program is distributed under GNU Public License *
* Please read the file COPYING for copyright information. *
**********************************************************************
Description: memoserv module
*/
#include "module.h"
#define MEMOSERV
#include "memoserv.h"
#include "path.h"
#include "my_sql.h"
#include "dbconf.h"
#include "lang/common.lh"
#include "lang/memoserv.lh"
/* module, version, description */
SVS_Module mod_info = {"memoserv", "5.0", "memoserv core module" };
#define DB_VERSION 4
/* ChangeLog
5.0 - #5: split memoserv with a memoserv options table
Added memoserv.4.sql changes
4.0 - 0000305: foreign keys for data integrity
3.0 - 0000265: remove nickserv cache system
*/
/* functions and events we require */
int e_nick_identify;
int mysql_connection;
int irc;
int e_expire = -1;
MOD_REQUIRES
MOD_FUNC(dbconf_get_or_build)
MOD_FUNC(irc)
MOD_FUNC(mysql_connection)
MOD_FUNC(e_nick_identify)
MOD_FUNC(e_expire) /* we need this to run the expire routines */
MOD_END
/* functionsa and events we provide */
ServiceUser* memoserv_suser(void); /* the memoserv user */
MOD_PROVIDES
MEMOSERV_FUNCTIONS
MOD_END
/* Local config */
static char* Nick;
static char* Username;
static char* Hostname;
static char* Realname;
static char* LogChan;
static int MaxMemosPerUser;
static int DefaultBuddyQuota;
static char* DefaultOptions;
static int ExpireTime = 0;
/* Local config flags */
static u_int32_t default_options = 0;
DBCONF_PROVIDES
DBCONF_WORD(Nick, "MemoServ", "Memoserv service nick")
DBCONF_WORD(Username, "Services", "Memoserv service username")
DBCONF_WORD(Hostname, "PTlink.net", "Memoserv service hostname")
DBCONF_STR(Realname, "Memoserv Service", "Memoserv service real name")
DBCONF_WORD_OPT(LogChan, "#Services.log", "Memoserv log channel")
DBCONF_INT(MaxMemosPerUser, "20","Max number of memos per user")
DBCONF_INT(DefaultBuddyQuota, "10",
"Number of memos to be kept exclusive for buddies")
DBCONF_TIME(ExpireTime, "90d",
"How long memos will be kept before expiring ?\n"
"Please note that save memos will not expire")
DBCONF_STR(DefaultOptions, "", "Default memoserv options")
DBCONF_END
/* internal variables */
ServiceUser msu;
int ms_log;
/* internal functions */
static int sql_upgrade(int version, int post);
/* core events */
void ev_ms_nick_identify(IRC_User* u, u_int32_t *snid);
int ev_ms_expire(void* dummy1, void* dummy2);
/* commands */
void ms_unknown(IRC_User* s, IRC_User* t);
int mod_rehash(void)
{
if(dbconf_get_or_build(mod_info.name, dbconf_provides) < 0 )
{
errlog("Error reading dbconf!");
return -1;
}
if(DefaultOptions)
{
char *wrong = validate_options(DefaultOptions, memoserv_options, &default_options);
if(wrong)
errlog("Ignoring unknown memoserv default option: %s", wrong);
}
return 0;
}
int mod_load(void)
{
/* first try to open the log file */
ms_log = log_open("memoserv","memoserv");
if(ms_log<0)
{
errlog("Could not open memoserv log file!");
return -1;
}
if(sql_check_inst_upgrade(mod_info.name, DB_VERSION, sql_upgrade) < 0 )
return -4;
/* Create the memoserv client */
msu.u = irc_CreateLocalUser(Nick, Username, Hostname, Hostname,
Realname,"+ro");
/* MS should join the log chan */
if(LogChan)
{
IRC_Chan *chan;
log_set_irc(ms_log, Nick, LogChan);
chan = irc_ChanJoin(msu.u, LogChan, CU_MODE_ADMIN | CU_MODE_OP );
irc_ChanMode(msu.u, chan, "+Ostn");
}
irc_AddUMsgEvent(msu.u, "*", (void*) ms_unknown); /* any other msg handler */
/* Add actions */
mod_add_event_action(e_nick_identify, (ActionHandler) ev_ms_nick_identify);
if(ExpireTime == 0)
stdlog(L_INFO, "ExpireTime is not set, memos will not expire");
else
mod_add_event_action(e_expire, (ActionHandler) ev_ms_expire);
return 0;
}
void
mod_unload(void)
{
mod_del_event_action(e_expire, (ActionHandler) ev_ms_nick_identify);
if(ExpireTime)
mod_del_event_action(e_expire, (ActionHandler) ev_ms_expire);
/* remove memoserv and all associated events */
irc_QuitLocalUser(msu.u, "Removing service");
}
void ms_unknown(IRC_User* s, IRC_User* t)
{
send_lang(t, s, UNKNOWN_COMMAND, irc_GetLastMsgCmd());
}
void ev_ms_nick_identify(IRC_User* u, u_int32_t *snid)
{
int nc = unread_memos_count(*snid);
if(nc > 0)
send_lang(u, msu.u, YOU_HAVE_X_UNREAD_MEMOS, nc);
}
/* to return the memoserv client */
ServiceUser* memoserv_suser(void)
{
return &msu;
}
/* return count of memos for a given user */
int memos_count(u_int32_t snid)
{
MYSQL_RES* res;
MYSQL_ROW row;
int count = 0;
res = sql_query("SELECT count(*) FROM memoserv WHERE owner_snid=%d", snid);
row = sql_next_row(res);
if(row)
count = atoi(row[0]);
sql_free(res);
return count;
}
/* return count of unread memos for a given user */
int unread_memos_count(u_int32_t snid)
{
MYSQL_RES* res;
MYSQL_ROW row;
int count = 0;
res = sql_query("SELECT count(*) FROM memoserv WHERE owner_snid=%d AND flags & %d",
snid, MFL_UNREAD);
row = sql_next_row(res);
if(row)
count = atoi(row[0]);
sql_free(res);
return count;
}
/* this version takes care of sql upgrades */
int sql_upgrade(int version, int post)
{
MYSQL_RES* res;
MYSQL_ROW row;
switch(version)
{
case 2:
if(post) /* Upgrading to version 2, need to regenerate ids */
{
u_int32_t id = 1;
u_int32_t osnid = 0;
u_int32_t smid = 0;
u_int32_t maxid = 0;
log_log(ms_log, mod_info.name, "Regenerating memo ids");
/* we need this to avoid id collisions */
res = sql_query("SELECT id FROM memoserv ORDER BY id DESC LIMIT 1");
row = sql_next_row(res);
if(row)
maxid = atoi(row[0]);
sql_free(res);
sql_execute("UPDATE memoserv SET id=id+%d WHERE id<%d",
maxid, MaxMemosPerUser+2);
res = sql_query("SELECT id, owner_snid FROM memoserv ORDER BY owner_snid");
while((row = sql_next_row(res)))
{
smid = atoi(row[0]);
if(osnid != atoi(row[1]))
id = 1;
osnid = atoi(row[1]);
sql_execute("UPDATE memoserv SET id=%d"
" WHERE id=%d AND owner_snid=%d", id, smid, osnid);
++id;
}
sql_free(res);
log_log(ms_log, mod_info.name, "Memo ids were generated");
}
break;
case 3: /* pre-validation of integrity rules */
if(!post) /* we need to check for "lost" memos */
{
int rowc = 0;
res = sql_query("SELECT memoserv.owner_snid FROM memoserv"
" LEFT JOIN nickserv ON (memoserv.owner_snid = nickserv.snid)"
" WHERE memoserv.owner_snid IS NOT NULL AND nickserv.snid IS NULL");
while((row = sql_next_row(res)))
{
log_log(ms_log, mod_info.name,
"Deleting memos owned by deleted nick %s", row[0]);
sql_execute("DELETE FROM memoserv WHERE owner_snid=%s", row[0]);
++rowc;
}
if(rowc)
log_log(ms_log, mod_info.name, "Removed %d lost memos(s)", rowc);
sql_free(res);
rowc = 0;
res = sql_query("SELECT memoserv.sender_snid FROM memoserv"
" LEFT JOIN nickserv ON (memoserv.sender_snid = nickserv.snid)"
" WHERE memoserv.sender_snid IS NOT NULL AND nickserv.snid IS NULL");
while((row = sql_next_row(res)))
{
if(atoi(row[0]) == 0) /* this is corrected by the upgrade sql */
continue;
log_log(ms_log, mod_info.name,
"Removing sender from lost nick %s", row[0]);
sql_execute("UPDATE memoserv SET sender_snid=NULL"
" WHERE sender_snid=%s", row[0]);
++rowc;
}
if(rowc)
log_log(ms_log, mod_info.name, "Removed %d lost sender(s)", rowc);
sql_free(res);
}
}
return 1;
}
/*
* Returns the options associated with a nick
*/
int memoserv_get_options(u_int32_t snid, int* maxmemos, int* bquota, u_int32_t* flags)
{
MYSQL_RES* res;
MYSQL_ROW row;
*maxmemos = MaxMemosPerUser;
*bquota = DefaultBuddyQuota;
*flags = default_options;
res = sql_query("SELECT maxmemos, bquota, flags "
"FROM memoserv_options WHERE snid=%d", snid);
/* upgrade/memoserv was unloaded ? lets try to insert it */
if((row = sql_next_row(res)))
{
int c = 0;
*maxmemos = atoi(row[c++]);
*bquota = atoi(row[c++]);
*flags = atoi(row[c++]);
sql_free(res);
}
else /* upgrade/memoserv was unloaded ? lets try to insert it */
{
sql_free(res);
sqlb_init("memoserv_options");
sqlb_add_int("snid", snid);
sqlb_add_int("maxmemos", *maxmemos);
sqlb_add_int("bquota", *bquota);
sqlb_add_int("flags", *flags);
if(sql_execute("%s", sqlb_insert()) < 0)
{
log_log(ms_log, mod_info.name, "Unable to insert options for nick %d", snid);
return 0;
}
}
return 1;
}
int ev_ms_expire(void* dummy1, void* dummy2)
{
sql_execute("DELETE FROM memoserv WHERE (flags & %d) = 0"
" AND t_send<%d", MFL_SAVED, irc_CurrentTime - ExpireTime);
return 1;
}
syntax highlighted by Code2HTML, v. 0.9.1