mirror of
https://github.com/anope/anope.git
synced 2026-06-27 23:56:39 +02:00
a08b3ec592
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@2674 5417fbe8-f217-4b02-8779-1006273d7864
429 lines
11 KiB
C
429 lines
11 KiB
C
/* MemoServ functions.
|
|
*
|
|
* (C) 2003-2009 Anope Team
|
|
* Contact us at team@anope.org
|
|
*
|
|
* Please read COPYING and README for further details.
|
|
*
|
|
* Based on the original code of Epona by Lara.
|
|
* Based on the original code of Services by Andy Church.
|
|
*
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
#include "services.h"
|
|
#include "pseudo.h"
|
|
|
|
/*************************************************************************/
|
|
/* *INDENT-OFF* */
|
|
|
|
E void moduleAddMemoServCmds();
|
|
static void new_memo_mail(NickCore *nc, Memo *m);
|
|
E void rsend_notify(User *u, Memo *m, const char *chan);
|
|
|
|
/*************************************************************************/
|
|
|
|
void moduleAddMemoServCmds() {
|
|
ModuleManager::LoadModuleList(Config.MemoServCoreModules);
|
|
}
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
/* *INDENT-ON* */
|
|
|
|
/**
|
|
* MemoServ initialization.
|
|
* @return void
|
|
*/
|
|
void ms_init()
|
|
{
|
|
moduleAddMemoServCmds();
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
/**
|
|
* memoserv: Main MemoServ routine.
|
|
* Note that the User structure passed to the do_* routines will
|
|
* always be valid (non-NULL) and will always have a valid
|
|
* NickInfo pointer in the `ni' field.
|
|
* @param u User Struct
|
|
* @param buf Buffer containing the privmsg
|
|
* @return void
|
|
*/
|
|
void memoserv(User * u, char *buf)
|
|
{
|
|
const char *cmd, *s;
|
|
|
|
cmd = strtok(buf, " ");
|
|
if (!cmd) {
|
|
return;
|
|
} else if (stricmp(cmd, "\1PING") == 0) {
|
|
if (!(s = strtok(NULL, ""))) {
|
|
s = "";
|
|
}
|
|
ircdproto->SendCTCP(findbot(Config.s_MemoServ), u->nick, "PING %s", s);
|
|
} else {
|
|
mod_run_cmd(Config.s_MemoServ, u, MEMOSERV, cmd);
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
/**
|
|
* check_memos: See if the given user has any unread memos, and send a
|
|
* NOTICE to that user if so (and if the appropriate flag is
|
|
* set).
|
|
* @param u User Struct
|
|
* @return void
|
|
*/
|
|
void check_memos(User * u)
|
|
{
|
|
NickCore *nc;
|
|
unsigned i, newcnt = 0;
|
|
|
|
if (!u) {
|
|
if (debug) {
|
|
alog("debug: check_memos called with NULL values");
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!(nc = u->nc) || !u->IsRecognized() ||
|
|
!(nc->HasFlag(NI_MEMO_SIGNON))) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < nc->memos.memos.size(); i++) {
|
|
if (nc->memos.memos[i]->HasFlag(MF_UNREAD))
|
|
newcnt++;
|
|
}
|
|
if (newcnt > 0) {
|
|
notice_lang(Config.s_MemoServ, u,
|
|
newcnt == 1 ? MEMO_HAVE_NEW_MEMO : MEMO_HAVE_NEW_MEMOS,
|
|
newcnt);
|
|
if (newcnt == 1 && (nc->memos.memos[i - 1]->HasFlag(MF_UNREAD))) {
|
|
notice_lang(Config.s_MemoServ, u, MEMO_TYPE_READ_LAST, Config.s_MemoServ);
|
|
} else if (newcnt == 1) {
|
|
for (i = 0; i < nc->memos.memos.size(); i++) {
|
|
if (nc->memos.memos[i]->HasFlag(MF_UNREAD))
|
|
break;
|
|
}
|
|
notice_lang(Config.s_MemoServ, u, MEMO_TYPE_READ_NUM, Config.s_MemoServ,
|
|
nc->memos.memos[i]->number);
|
|
} else {
|
|
notice_lang(Config.s_MemoServ, u, MEMO_TYPE_LIST_NEW, Config.s_MemoServ);
|
|
}
|
|
}
|
|
if (nc->memos.memomax > 0 && nc->memos.memos.size() >= nc->memos.memomax) {
|
|
if (nc->memos.memos.size() > nc->memos.memomax)
|
|
notice_lang(Config.s_MemoServ, u, MEMO_OVER_LIMIT, nc->memos.memomax);
|
|
else
|
|
notice_lang(Config.s_MemoServ, u, MEMO_AT_LIMIT, nc->memos.memomax);
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
/*********************** MemoServ private routines ***********************/
|
|
/*************************************************************************/
|
|
|
|
/**
|
|
* Return the MemoInfo corresponding to the given nick or channel name.
|
|
* @param name Name to check
|
|
* @param ischan - the result its a channel will be stored in here
|
|
* @param isforbid - the result if its forbidden will be stored in here
|
|
* @return `ischan' 1 if the name was a channel name, else 0.
|
|
* @return `isforbid' 1 if the name is forbidden, else 0.
|
|
*/
|
|
MemoInfo *getmemoinfo(const char *name, int *ischan, int *isforbid)
|
|
{
|
|
if (*name == '#') {
|
|
ChannelInfo *ci;
|
|
if (ischan)
|
|
*ischan = 1;
|
|
ci = cs_findchan(name);
|
|
if (ci) {
|
|
if (!(ci->HasFlag(CI_FORBIDDEN))) {
|
|
*isforbid = 0;
|
|
return &ci->memos;
|
|
} else {
|
|
*isforbid = 1;
|
|
return NULL;
|
|
}
|
|
} else {
|
|
*isforbid = 0;
|
|
return NULL;
|
|
}
|
|
} else {
|
|
NickAlias *na;
|
|
if (ischan)
|
|
*ischan = 0;
|
|
na = findnick(name);
|
|
if (na) {
|
|
if (!na->HasFlag(NS_FORBIDDEN)) {
|
|
*isforbid = 0;
|
|
return &na->nc->memos;
|
|
} else {
|
|
*isforbid = 1;
|
|
return NULL;
|
|
}
|
|
} else {
|
|
*isforbid = 0;
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
/**
|
|
* Split from do_send, this way we can easily send a memo from any point
|
|
* @param u User Struct
|
|
* @param name Target of the memo
|
|
* @param text Memo Text
|
|
* @param z type see info
|
|
* 0 - reply to user
|
|
* 1 - silent
|
|
* 2 - silent with no delay timer
|
|
* 3 - reply to user and request read receipt
|
|
* @return void
|
|
*/
|
|
void memo_send(User * u, const char *name, const char *text, int z)
|
|
{
|
|
int ischan;
|
|
int isforbid;
|
|
Memo *m;
|
|
MemoInfo *mi;
|
|
time_t now = time(NULL);
|
|
char *source = u->nc->display;
|
|
int is_servoper = u->nc && u->nc->IsServicesOper();
|
|
|
|
if (readonly) {
|
|
notice_lang(Config.s_MemoServ, u, MEMO_SEND_DISABLED);
|
|
} else if (!text) {
|
|
if (z == 0)
|
|
syntax_error(Config.s_MemoServ, u, "SEND", MEMO_SEND_SYNTAX);
|
|
|
|
if (z == 3)
|
|
syntax_error(Config.s_MemoServ, u, "RSEND", MEMO_RSEND_SYNTAX);
|
|
|
|
} else if (!nick_identified(u) && !u->IsRecognized()) {
|
|
if (z == 0 || z == 3)
|
|
notice_lang(Config.s_MemoServ, u, NICK_IDENTIFY_REQUIRED, Config.s_NickServ);
|
|
|
|
} else if (!(mi = getmemoinfo(name, &ischan, &isforbid))) {
|
|
if (z == 0 || z == 3) {
|
|
if (isforbid) {
|
|
notice_lang(Config.s_MemoServ, u,
|
|
ischan ? CHAN_X_FORBIDDEN :
|
|
NICK_X_FORBIDDEN, name);
|
|
} else {
|
|
notice_lang(Config.s_MemoServ, u,
|
|
ischan ? CHAN_X_NOT_REGISTERED :
|
|
NICK_X_NOT_REGISTERED, name);
|
|
}
|
|
}
|
|
} else if (z != 2 && Config.MSSendDelay > 0 &&
|
|
u && u->lastmemosend + Config.MSSendDelay > now) {
|
|
u->lastmemosend = now;
|
|
if (z == 0)
|
|
notice_lang(Config.s_MemoServ, u, MEMO_SEND_PLEASE_WAIT, Config.MSSendDelay);
|
|
|
|
if (z == 3)
|
|
notice_lang(Config.s_MemoServ, u, MEMO_RSEND_PLEASE_WAIT,
|
|
Config.MSSendDelay);
|
|
|
|
} else if (mi->memomax == 0 && !is_servoper) {
|
|
if (z == 0 || z == 3)
|
|
notice_lang(Config.s_MemoServ, u, MEMO_X_GETS_NO_MEMOS, name);
|
|
|
|
} else if (mi->memomax > 0 && mi->memos.size() >= mi->memomax
|
|
&& !is_servoper) {
|
|
if (z == 0 || z == 3)
|
|
notice_lang(Config.s_MemoServ, u, MEMO_X_HAS_TOO_MANY_MEMOS, name);
|
|
|
|
} else {
|
|
u->lastmemosend = now;
|
|
m = new Memo;
|
|
mi->memos.push_back(m);
|
|
strscpy(m->sender, source, NICKMAX);
|
|
if (mi->memos.size() > 1) {
|
|
m->number = mi->memos[mi->memos.size() - 2]->number + 1;
|
|
if (m->number < 1) {
|
|
unsigned i;
|
|
for (i = 0; i < mi->memos.size(); i++) {
|
|
mi->memos[i]->number = i + 1;
|
|
}
|
|
}
|
|
} else {
|
|
m->number = 1;
|
|
}
|
|
m->time = time(NULL);
|
|
m->text = sstrdup(text);
|
|
m->SetFlag(MF_UNREAD);
|
|
/* Set notify sent flag - DrStein */
|
|
if (z == 2) {
|
|
m->SetFlag(MF_NOTIFYS);
|
|
}
|
|
/* Set receipt request flag */
|
|
if (z == 3)
|
|
m->SetFlag(MF_RECEIPT);
|
|
if (z == 0 || z == 3)
|
|
notice_lang(Config.s_MemoServ, u, MEMO_SENT, name);
|
|
if (!ischan) {
|
|
NickAlias *na;
|
|
NickCore *nc = (findnick(name))->nc;
|
|
|
|
if (Config.MSNotifyAll) {
|
|
if ((nc->HasFlag(NI_MEMO_RECEIVE))
|
|
&& get_ignore(name) == NULL) {
|
|
int i;
|
|
|
|
for (i = 0; i < nc->aliases.count; i++) {
|
|
na = static_cast<NickAlias *>(nc->aliases.list[i]);
|
|
if (finduser(na->nick) && nick_identified(finduser(na->nick)))
|
|
notice_lang(Config.s_MemoServ, finduser(na->nick),
|
|
MEMO_NEW_MEMO_ARRIVED, source,
|
|
Config.s_MemoServ, m->number);
|
|
}
|
|
} else {
|
|
if ((u = finduser(name)) && nick_identified(u)
|
|
&& (nc->HasFlag(NI_MEMO_RECEIVE)))
|
|
notice_lang(Config.s_MemoServ, u, MEMO_NEW_MEMO_ARRIVED,
|
|
source, Config.s_MemoServ, m->number);
|
|
} /* if (flags & MEMO_RECEIVE) */
|
|
}
|
|
/* if (MSNotifyAll) */
|
|
/* let's get out the mail if set in the nickcore - certus */
|
|
if (nc->HasFlag(NI_MEMO_MAIL))
|
|
new_memo_mail(nc, m);
|
|
} else {
|
|
struct c_userlist *cu, *next;
|
|
Channel *c;
|
|
|
|
if (Config.MSNotifyAll && (c = findchan(name))) {
|
|
for (cu = c->users; cu; cu = next) {
|
|
next = cu->next;
|
|
if (check_access(cu->user, c->ci, CA_MEMO)) {
|
|
if (cu->user->nc
|
|
&& (cu->user->nc->HasFlag(NI_MEMO_RECEIVE))
|
|
&& get_ignore(cu->user->nick) == NULL) {
|
|
notice_lang(Config.s_MemoServ, cu->user,
|
|
MEMO_NEW_X_MEMO_ARRIVED,
|
|
c->ci->name, Config.s_MemoServ,
|
|
c->ci->name, m->number);
|
|
}
|
|
}
|
|
}
|
|
} /* MSNotifyAll */
|
|
} /* if (!ischan) */
|
|
} /* if command is valid */
|
|
}
|
|
|
|
/*************************************************************************/
|
|
/**
|
|
* Delete a memo by number.
|
|
* @param mi Memoinfo struct
|
|
* @param num Memo number to delete
|
|
* @return int 1 if the memo was found, else 0.
|
|
*/
|
|
int delmemo(MemoInfo * mi, int num)
|
|
{
|
|
unsigned i;
|
|
if (mi->memos.empty()) return 0;
|
|
|
|
for (i = 0; i < mi->memos.size(); i++) {
|
|
if (mi->memos[i]->number == num)
|
|
break;
|
|
}
|
|
if (i < mi->memos.size()) {
|
|
delete [] mi->memos[i]->text; /* Deallocate memo text memory */
|
|
delete mi->memos[i]; /* Deallocate the memo itself */
|
|
mi->memos.erase(mi->memos.begin() + i); /* Remove the memo pointer from the vector */
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static void new_memo_mail(NickCore * nc, Memo * m)
|
|
{
|
|
MailInfo *mail = NULL;
|
|
|
|
if (!nc || !m)
|
|
return;
|
|
|
|
mail = MailMemoBegin(nc);
|
|
if (!mail) {
|
|
return;
|
|
}
|
|
fprintf(mail->pipe, getstring(MEMO_MAIL_TEXT1), nc->display);
|
|
fprintf(mail->pipe, "\n");
|
|
fprintf(mail->pipe, getstring(MEMO_MAIL_TEXT2), m->sender,
|
|
m->number);
|
|
fprintf(mail->pipe, "\n\n");
|
|
fprintf(mail->pipe, "%s", getstring(MEMO_MAIL_TEXT3));
|
|
fprintf(mail->pipe, "\n\n");
|
|
fprintf(mail->pipe, "%s", m->text);
|
|
fprintf(mail->pipe, "\n");
|
|
MailEnd(mail);
|
|
return;
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/* Send receipt notification to sender. */
|
|
|
|
void rsend_notify(User * u, Memo * m, const char *chan)
|
|
{
|
|
NickAlias *na;
|
|
NickCore *nc;
|
|
char text[256];
|
|
const char *fmt;
|
|
|
|
/* Only send receipt if memos are allowed */
|
|
if ((!readonly))
|
|
{
|
|
|
|
/* Get nick alias for sender */
|
|
na = findnick(m->sender);
|
|
|
|
if (!na) {
|
|
return;
|
|
}
|
|
|
|
/* Get nick core for sender */
|
|
nc = na->nc;
|
|
|
|
if (!nc) {
|
|
return;
|
|
}
|
|
|
|
/* Text of the memo varies if the recepient was a
|
|
nick or channel */
|
|
if (chan) {
|
|
fmt = getstring(na, MEMO_RSEND_CHAN_MEMO_TEXT);
|
|
snprintf(text, sizeof(text), fmt, chan);
|
|
} else {
|
|
fmt = getstring(na, MEMO_RSEND_NICK_MEMO_TEXT);
|
|
snprintf(text, sizeof(text), "%s", fmt);
|
|
}
|
|
|
|
/* Send notification */
|
|
memo_send(u, m->sender, text, 2);
|
|
|
|
/* Notify recepient of the memo that a notification has
|
|
been sent to the sender */
|
|
notice_lang(Config.s_MemoServ, u, MEMO_RSEND_USER_NOTIFICATION,
|
|
nc->display);
|
|
}
|
|
|
|
/* Remove receipt flag from the original memo */
|
|
m->UnsetFlag(MF_RECEIPT);
|
|
|
|
return;
|
|
}
|