/* HelpServ functions.
*
* IRC Services is copyright (c) 1996-2007 Andrew Church.
* E-mail: <achurch@achurch.org>
* Parts written by Andrew Kempe and others.
* This program is free but copyrighted software; see the file COPYING for
* details.
*/
#include "services.h"
#include "modules.h"
#include "conffile.h"
#include "language.h"
#include <sys/stat.h>
/*************************************************************************/
static Module *module;
static char *s_HelpServ;
static char *desc_HelpServ;
static char *HelpDir;
/*************************************************************************/
/*************************** HelpServ routine ****************************/
/*************************************************************************/
/* Main HelpServ routine. */
static void helpserv(const char *source, char *topic)
{
FILE *f;
struct stat st;
char buf[PATH_MAX+1], *ptr;
const char *s;
char *old_topic; /* an unclobbered (by strtok) copy */
User *u;
if (strnicmp(topic, "\1PING ", 6) == 0) {
s = strtok(topic, " ");
if (!(s = strtok(NULL, "")))
s = "\1";
notice(s_HelpServ, source, "\1PING %s", s);
return;
}
old_topic = sstrdup(topic);
u = get_user(source);
/* As we copy path parts, (1) lowercase everything and (2) make sure
* we don't let any special characters through -- this includes '.'
* (which could get parent dir) or '/' (which couldn't _really_ do
* anything nasty if we keep '.' out, but better to be on the safe
* side). Special characters turn into '_'.
*/
strscpy(buf, HelpDir, sizeof(buf));
ptr = buf + strlen(buf);
for (s = strtok(topic, " "); s && ptr-buf < sizeof(buf)-1;
s = strtok(NULL, " ")) {
*ptr++ = '/';
while (*s && ptr-buf < sizeof(buf)-1) {
if (*s == '.' || *s == '/')
*ptr++ = '_';
else
*ptr++ = tolower(*s);
s++;
}
*ptr = 0;
}
/* If we end up at a directory, go for an "index" file/dir if
* possible.
*/
while (ptr-buf < sizeof(buf)-6
&& stat(buf, &st) == 0 && S_ISDIR(st.st_mode)) {
strcpy(ptr, "/index");
ptr += strlen(ptr);
}
/* Send the file, if it exists.
*/
if (!(f = fopen(buf, "r"))) {
if (debug)
module_log_perror("debug: Cannot open help file %s", buf);
if (u) {
notice_lang(s_HelpServ, u, NO_HELP_AVAILABLE, old_topic);
} else {
notice(s_HelpServ, source,
"Sorry, no help available for \2%s\2.", old_topic);
}
} else {
while (fgets(buf, sizeof(buf), f)) {
s = strtok(buf, "\n");
/* Use this odd construction to prevent any %'s in the text from
* doing weird stuff to the output. Also replace blank lines by
* spaces (see send.c/notice_list() for an explanation of why).
*/
notice(s_HelpServ, source, "%s", s ? s : " ");
}
fclose(f);
}
free(old_topic);
}
/*************************************************************************/
/**************************** Event callbacks ****************************/
/*************************************************************************/
/* Handler for introducing nicks. */
static int do_introduce(const char *nick)
{
if (!nick || irc_stricmp(nick, s_HelpServ) == 0) {
send_nick(s_HelpServ, ServiceUser, ServiceHost, ServerName,
desc_HelpServ, pseudoclient_modes);
if (nick)
return 1;
}
return 0;
}
/*************************************************************************/
/* Handler for PRIVMSGs. */
static int do_privmsg(const char *source, const char *target, char *buf)
{
if (irc_stricmp(target, s_HelpServ) == 0) {
helpserv(source, buf);
return 1;
}
return 0;
}
/*************************************************************************/
/* Handler for WHOIS's. */
static int do_whois(const char *source, char *who, char *extra)
{
if (irc_stricmp(who, s_HelpServ) == 0) {
send_cmd(ServerName, "311 %s %s %s %s * :%s", source, who,
ServiceUser, ServiceHost, desc_HelpServ);
send_cmd(ServerName, "312 %s %s %s :%s", source, who,
ServerName, ServerDesc);
send_cmd(ServerName, "318 %s %s End of /WHOIS response.", source, who);
return 1;
} else {
return 0;
}
}
/*************************************************************************/
/***************************** Module stuff ******************************/
/*************************************************************************/
const int32 module_version = MODULE_VERSION_CODE;
ConfigDirective module_config[] = {
{ "HelpDir", { { CD_STRING, CF_DIRREQ, &HelpDir } } },
{ "HelpServName", { { CD_STRING, CF_DIRREQ, &s_HelpServ },
{ CD_STRING, 0, &desc_HelpServ } } },
{ NULL }
};
/*************************************************************************/
static int do_reconfigure(int after_configure)
{
static char old_s_HelpServ[NICKMAX];
static char *old_desc_HelpServ = NULL;
if (!after_configure) {
/* Before reconfiguration: save old values. */
free(old_desc_HelpServ);
strscpy(old_s_HelpServ, s_HelpServ, NICKMAX);
old_desc_HelpServ = strdup(desc_HelpServ);
} else {
/* After reconfiguration: handle value changes. */
if (strcmp(old_s_HelpServ, s_HelpServ) != 0)
send_nickchange(old_s_HelpServ, s_HelpServ);
if (!old_desc_HelpServ || strcmp(old_desc_HelpServ,desc_HelpServ) != 0)
send_namechange(s_HelpServ, desc_HelpServ);
free(old_desc_HelpServ);
old_desc_HelpServ = NULL;
} /* if (!after_configure) */
return 0;
}
/*************************************************************************/
int init_module(Module *module_)
{
module = module_;
if (!add_callback(NULL, "reconfigure", do_reconfigure)
|| !add_callback(NULL, "introduce_user", do_introduce)
|| !add_callback(NULL, "m_privmsg", do_privmsg)
|| !add_callback(NULL, "m_whois", do_whois)
) {
exit_module(0);
return 0;
}
if (linked)
do_introduce(NULL);
return 1;
}
/*************************************************************************/
int exit_module(int shutdown_unused)
{
#ifdef CLEAN_COMPILE
shutdown_unused = shutdown_unused;
#endif
if (linked)
send_cmd(s_HelpServ, "QUIT :");
remove_callback(NULL, "m_whois", do_whois);
remove_callback(NULL, "m_privmsg", do_privmsg);
remove_callback(NULL, "introduce_user", do_introduce);
remove_callback(NULL, "reconfigure", do_reconfigure);
return 1;
}
/*************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1