diff options
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | doc/reference.conf | 18 | ||||
-rw-r--r-- | help/stats | 1 | ||||
-rw-r--r-- | include/conf.h | 5 | ||||
-rw-r--r-- | include/message.h | 63 | ||||
-rw-r--r-- | include/motd.h | 95 | ||||
-rw-r--r-- | include/numeric.h | 3 | ||||
-rw-r--r-- | modules/m_motd.c | 2 | ||||
-rw-r--r-- | modules/m_rehash.c | 5 | ||||
-rw-r--r-- | modules/m_stats.c | 4 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/Makefile.in | 8 | ||||
-rw-r--r-- | src/conf.c | 3 | ||||
-rw-r--r-- | src/conf_lexer.l | 1 | ||||
-rw-r--r-- | src/conf_parser.y | 39 | ||||
-rw-r--r-- | src/ircd.c | 9 | ||||
-rw-r--r-- | src/message.c | 245 | ||||
-rw-r--r-- | src/motd.c | 561 | ||||
-rw-r--r-- | src/numeric.c | 2 | ||||
-rw-r--r-- | src/s_user.c | 21 |
20 files changed, 826 insertions, 262 deletions
@@ -1,5 +1,5 @@ #! /bin/sh -# From configure.ac Id: configure.ac 2102 2013-05-19 13:25:09Z michael . +# From configure.ac Id: configure.ac 2109 2013-05-23 19:39:03Z michael . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for ircd-hybrid 8.1.0. # diff --git a/doc/reference.conf b/doc/reference.conf index 6fd28ef..6b75d02 100644 --- a/doc/reference.conf +++ b/doc/reference.conf @@ -292,6 +292,24 @@ class { }; /* + * motd {}: specifies various MOTD files. Applies to local users only. + */ +motd { + /* + * mask: multiple mask entries are permitted. Mask can either be + * a class name or a hostname. + */ + mask = "*.at"; + mask = "*.de"; + mask = "*.ch"; + + /* + * file: path top the actual motd file. + */ + file = "/usr/local/ircd/etc/german.motd"; +}; + +/* * listen {}: contains information about the ports ircd listens on */ listen { @@ -30,6 +30,7 @@ X h - Shows ircd callback statistics * q - Shows resv'd nicks and channels * r - Shows resource usage by ircd * s - Shows the server cache +* T - Shows configured Message Of The Day files * t - Shows generic server stats * U - Shows shared blocks (Old U: lines) u - Shows server uptime diff --git a/include/conf.h b/include/conf.h index 311ad38..e1090bb 100644 --- a/include/conf.h +++ b/include/conf.h @@ -26,7 +26,7 @@ #define INCLUDED_s_conf_h #include "config.h" #include "ircd_defs.h" -#include "motd.h" /* MessageFile */ +#include "message.h" /* MessageFile */ #include "client.h" #include "hook.h" #include "conf_class.h" @@ -209,11 +209,12 @@ struct config_file_entry const char *xlinefile; const char *dlinefile; const char *resvfile; + char *mpath; + char *rpath; char *egdpool_path; char *service_name; - MessageFile motd; MessageFile linksfile; int gline_min_cidr; diff --git a/include/message.h b/include/message.h new file mode 100644 index 0000000..0b76cb0 --- /dev/null +++ b/include/message.h @@ -0,0 +1,63 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * motd.h: A header for the MOTD functions. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * $Id: motd.h 1737 2013-01-14 17:37:55Z michael $ + */ + +#ifndef INCLUDED_message_h +#define INCLUDED_message_h +#include "ircd_defs.h" + + +#define MESSAGELINELEN 256 + +struct MessageFileLine +{ + struct MessageFileLine *next; + char line[MESSAGELINELEN + 1]; +}; + +typedef struct MessageFileLine MessageFileLine; + +typedef enum { + USER_LINKS, + ISSUPPORT +} MessageType; + +struct MessageFile +{ + MessageFileLine *contentsOfFile; + MessageType msgType; + char fileName[HYB_PATH_MAX + 1]; +}; + +typedef struct MessageFile MessageFile; + +struct Client; + +extern void init_message_file(MessageType, const char *, MessageFile *); +extern int send_message_file(struct Client *, MessageFile *); +extern int read_message_file(MessageFile *); +extern MessageFile *init_MessageLine(void); +extern void addto_MessageLine(MessageFile *, const char *); +extern void destroy_MessageLine(MessageFile *); + +#endif /* INCLUDED_motd_h */ diff --git a/include/motd.h b/include/motd.h index 4490b17..e78b64a 100644 --- a/include/motd.h +++ b/include/motd.h @@ -1,8 +1,8 @@ /* * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). - * motd.h: A header for the MOTD functions. * - * Copyright (C) 2002 by the past and present ircd coders, and others. + * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu> + * Copyright (C) 2013 by the Hybrid Development Team. * * 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 @@ -18,48 +18,81 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA - * - * $Id$ + */ + +/*! \file motd.h + * \brief Message-of-the-day manipulation implementation. + * \version $Id$ */ #ifndef INCLUDED_motd_h #define INCLUDED_motd_h -#include "ircd_defs.h" - +struct Client; -#define MESSAGELINELEN 256 +/** Type of MOTD. */ +enum MotdType +{ + MOTD_UNIVERSAL, /**< MOTD for all users */ + MOTD_HOSTMASK, /**< MOTD selected by hostmask */ + MOTD_IPMASK, /**< MOTD selected by IP mask */ + MOTD_CLASS /**< MOTD selected by connection class */ +}; -struct MessageFileLine +/** Entry for a single Message Of The Day (MOTD). */ +struct Motd { - struct MessageFileLine *next; - char line[MESSAGELINELEN + 1]; + dlink_node node; /**< Next MOTD in the linked list. */ + enum MotdType type; /**< Type of MOTD. */ + char *hostmask; /**< Hostmask if type==MOTD_HOSTMASK, + class name if type==MOTD_CLASS, + text IP mask if type==MOTD_IPMASK. */ + struct irc_ssaddr address; /**< Address if type==MOTD_IPMASK. */ + int addrbits; /**< Number of bits checked in Motd::address. */ + char *path; /**< Pathname of MOTD file. */ + int maxcount; /**< Number of lines for MOTD. */ + struct MotdCache *cache; /**< MOTD cache entry. */ }; -typedef struct MessageFileLine MessageFileLine; +/** Length of one MOTD line(80 chars + '\\0'). */ +#define MOTD_LINESIZE 81 +/** Maximum number of lines for MOTD */ +#define MOTD_MAXLINES 100 -typedef enum { - USER_MOTD, - USER_LINKS, - ISSUPPORT -} MotdType; - -struct MessageFile + +/** Cache entry for the contents of a MOTD file. */ +struct MotdCache { - MessageFileLine *contentsOfFile; - MotdType motdType; - char fileName[HYB_PATH_MAX + 1]; - char lastChangedDate[MAX_DATE_STRING + 1]; + dlink_node node; /**< Next MotdCache in list. */ + int ref; /**< Number of references to this entry. */ + char *path; /**< Pathname of file. */ + int maxcount; /**< Number of lines allocated for message. */ + struct tm modtime; /**< Last modification time from file. */ + int count; /**< Actual number of lines used in message. */ + char motd[1][MOTD_LINESIZE]; /**< Message body. */ }; -typedef struct MessageFile MessageFile; +/* motd_send sends a MOTD off to a user */ +extern void motd_send(struct Client *); -struct Client; +/* motd_signon sends a MOTD off to a newly-registered user */ +extern void motd_signon(struct Client *); + +/* motd_recache causes all the MOTD caches to be cleared */ +extern void motd_recache(void); + +/* motd_init initializes the MOTD routines, including reading the + * ircd.motd and remote.motd files into cache + */ +extern void motd_init(void); + +/* This routine adds a MOTD */ +extern void motd_add(const char *, const char *); + +/* This routine clears the list of MOTDs */ +extern void motd_clear(void); -extern void init_message_file(MotdType, const char *, struct MessageFile *); -extern int send_message_file(struct Client *, struct MessageFile *); -extern int read_message_file(MessageFile *); -extern MessageFile *init_MessageLine(void); -extern void addto_MessageLine(MessageFile *, const char *); -extern void destroy_MessageLine(MessageFile *); +/* This is called to report T-lines */ +extern void motd_report(struct Client *); +extern void motd_memory_count(struct Client *); -#endif /* INCLUDED_motd_h */ +#endif diff --git a/include/numeric.h b/include/numeric.h index 0f9bca6..6e9cad9 100644 --- a/include/numeric.h +++ b/include/numeric.h @@ -86,8 +86,7 @@ extern const char *form_str(unsigned int); #define RPL_STATSUPTIME 242 #define RPL_STATSOLINE 243 #define RPL_STATSHLINE 244 -/* 245 No longer used in ircd-hybrid */ -#define RPL_STATSSLINE 245 +#define RPL_STATSTLINE 245 #define RPL_STATSSERVICE 246 #define RPL_STATSXLINE 247 #define RPL_STATSULINE 248 diff --git a/modules/m_motd.c b/modules/m_motd.c index 805840f..4f30eb7 100644 --- a/modules/m_motd.c +++ b/modules/m_motd.c @@ -42,7 +42,7 @@ do_motd(struct Client *source_p) "MOTD requested by %s (%s@%s) [%s]", source_p->name, source_p->username, source_p->host, source_p->servptr->name); - send_message_file(source_p, &ConfigFileEntry.motd); + motd_send(source_p); } /* diff --git a/modules/m_rehash.c b/modules/m_rehash.c index 77f5633..8eebf1c 100644 --- a/modules/m_rehash.c +++ b/modules/m_rehash.c @@ -34,6 +34,7 @@ #include "send.h" #include "parse.h" #include "modules.h" +#include "motd.h" /* @@ -68,9 +69,9 @@ mo_rehash(struct Client *client_p, struct Client *source_p, else if (irccmp(parv[1], "MOTD") == 0) { sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, - "%s is forcing re-reading of MOTD file", + "%s is forcing re-reading of MOTD files", get_oper_name(source_p)); - read_message_file(&ConfigFileEntry.motd); + motd_recache(); found = 1; } diff --git a/modules/m_stats.c b/modules/m_stats.c index a903e92..12bb862 100644 --- a/modules/m_stats.c +++ b/modules/m_stats.c @@ -48,6 +48,7 @@ #include "whowas.h" #include "watch.h" #include "irc_res.h" +#include "motd.h" const char *from, *to; @@ -526,6 +527,7 @@ stats_memory(struct Client *source_p, int parc, char *parv[]) totww = wwu * sizeof(struct Client) + wwm; + motd_memory_count(source_p); count_ip_hash(&number_ips_stored,&mem_ips_stored); sendto_one(source_p, ":%s %d %s z :iphash %u(%llu)", me.name, RPL_STATSDEBUG, source_p->name, @@ -1562,7 +1564,7 @@ static const struct StatsStruct { 's', stats_service, 1, 0 }, { 'S', stats_service, 1, 0 }, { 't', stats_tstats, 1, 0 }, - { 'T', stats_tstats, 1, 0 }, + { 'T', motd_report, 1, 0 }, { 'u', stats_uptime, 0, 0 }, { 'U', stats_shared, 1, 0 }, { 'v', stats_servers, 1, 0 }, diff --git a/src/Makefile.am b/src/Makefile.am index ae67d4b..f119469 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -35,6 +35,7 @@ ircd_SOURCES = channel.c \ match.c \ memory.c \ mempool.c \ + message.c \ modules.c \ motd.c \ rng_mt.c \ diff --git a/src/Makefile.in b/src/Makefile.in index 0c3cc49..8773dcc 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -103,9 +103,9 @@ am_ircd_OBJECTS = channel.$(OBJEXT) channel_mode.$(OBJEXT) \ irc_string.$(OBJEXT) ircd.$(OBJEXT) ircd_signal.$(OBJEXT) \ list.$(OBJEXT) listener.$(OBJEXT) log.$(OBJEXT) \ match.$(OBJEXT) memory.$(OBJEXT) mempool.$(OBJEXT) \ - modules.$(OBJEXT) motd.$(OBJEXT) rng_mt.$(OBJEXT) \ - numeric.$(OBJEXT) packet.$(OBJEXT) parse.$(OBJEXT) \ - s_bsd_epoll.$(OBJEXT) s_bsd_poll.$(OBJEXT) \ + message.$(OBJEXT) modules.$(OBJEXT) motd.$(OBJEXT) \ + rng_mt.$(OBJEXT) numeric.$(OBJEXT) packet.$(OBJEXT) \ + parse.$(OBJEXT) s_bsd_epoll.$(OBJEXT) s_bsd_poll.$(OBJEXT) \ s_bsd_devpoll.$(OBJEXT) s_bsd_kqueue.$(OBJEXT) \ s_bsd_select.$(OBJEXT) restart.$(OBJEXT) resv.$(OBJEXT) \ rsa.$(OBJEXT) s_auth.$(OBJEXT) s_bsd.$(OBJEXT) \ @@ -374,6 +374,7 @@ ircd_SOURCES = channel.c \ match.c \ memory.c \ mempool.c \ + message.c \ modules.c \ motd.c \ rng_mt.c \ @@ -522,6 +523,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/match.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mempool.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modules.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/motd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/numeric.Po@am__quote@ @@ -53,6 +53,7 @@ #include "s_misc.h" #include "conf_db.h" #include "conf_class.h" +#include "motd.h" struct config_server_hide ConfigServerHide; @@ -1574,6 +1575,8 @@ clear_out_old_conf(void) } } + motd_clear(); + /* * don't delete the class table, rather mark all entries * for deletion. The table is cleaned up by class_delete_marked. - avalon diff --git a/src/conf_lexer.l b/src/conf_lexer.l index 783ce19..ccdf4cc 100644 --- a/src/conf_lexer.l +++ b/src/conf_lexer.l @@ -243,6 +243,7 @@ min_nonwildcard { return MIN_NONWILDCARD; } min_nonwildcard_simple { return MIN_NONWILDCARD_SIMPLE; } module { return MODULE; } modules { return MODULES; } +motd { return MOTD; } name { return NAME; } nchange { return T_NCHANGE; } need_ident { return NEED_IDENT; } diff --git a/src/conf_parser.y b/src/conf_parser.y index 4aeec9f..d247062 100644 --- a/src/conf_parser.y +++ b/src/conf_parser.y @@ -47,6 +47,7 @@ #include "resv.h" #include "numeric.h" #include "s_user.h" +#include "motd.h" #ifdef HAVE_LIBCRYPTO #include <openssl/rsa.h> @@ -231,6 +232,7 @@ reset_block_state(void) %token MIN_NONWILDCARD_SIMPLE %token MODULE %token MODULES +%token MOTD %token NAME %token NEED_IDENT %token NEED_PASSWORD @@ -385,6 +387,7 @@ conf_item: admin_entry | general_entry | gecos_entry | modules_entry + | motd_entry | error ';' | error '}' ; @@ -872,6 +875,42 @@ admin_description: DESCRIPTION '=' QSTRING ';' }; /*************************************************************************** + * motd section + ***************************************************************************/ +motd_entry: MOTD +{ + if (conf_parser_ctx.pass == 2) + reset_block_state(); +} '{' motd_items '}' ';' +{ + dlink_node *ptr = NULL; + + if (conf_parser_ctx.pass != 2) + break; + + if (!block_state.file.buf[0]) + break; + + DLINK_FOREACH(ptr, block_state.mask.list.head) + motd_add(ptr->data, block_state.file.buf); +}; + +motd_items: motd_items motd_item | motd_item; +motd_item: motd_mask | motd_file | error ';' ; + +motd_mask: MASK '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + dlinkAdd(xstrdup(yylval.string), make_dlink_node(), &block_state.mask.list); +}; + +motd_file: T_FILE '=' QSTRING ';' +{ + if (conf_parser_ctx.pass == 2) + strlcpy(block_state.file.buf, yylval.string, sizeof(block_state.file.buf)); +}; + +/*************************************************************************** * section logging ***************************************************************************/ logging_entry: T_LOG '{' logging_items '}' ';' ; @@ -56,7 +56,7 @@ #include "mempool.h" #include "hook.h" #include "ircd_getopt.h" -#include "motd.h" +#include "message.h" #include "supported.h" #include "watch.h" #include "conf_db.h" @@ -251,9 +251,9 @@ io_loop(void) } if (doremotd) { - read_message_file(&ConfigFileEntry.motd); + motd_recache(); sendto_realops_flags(UMODE_ALL, L_ALL, SEND_NOTICE, - "Got signal SIGUSR1, reloading ircd motd file"); + "Got signal SIGUSR1, reloading motd files"); doremotd = 0; } } @@ -306,10 +306,8 @@ initialize_global_set_options(void) static void initialize_message_files(void) { - init_message_file(USER_MOTD, MPATH, &ConfigFileEntry.motd); init_message_file(USER_LINKS, LIPATH, &ConfigFileEntry.linksfile); - read_message_file(&ConfigFileEntry.motd); read_message_file(&ConfigFileEntry.linksfile); init_isupport(); @@ -563,6 +561,7 @@ main(int argc, char *argv[]) initialize_server_capabs(); /* Set up default_server_capabs */ initialize_global_set_options(); channel_init(); + motd_init(); #ifdef HAVE_LIBGEOIP geoip_ctx = GeoIP_new(GEOIP_MEMORY_CACHE); #endif diff --git a/src/message.c b/src/message.c new file mode 100644 index 0000000..716cf8d --- /dev/null +++ b/src/message.c @@ -0,0 +1,245 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * motd.c: Message of the day functions. + * + * Copyright (C) 2002 by the past and present ircd coders, and others. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * $Id: motd.c 1834 2013-04-19 19:50:27Z michael $ + */ + +#include "stdinc.h" +#include "list.h" +#include "message.h" +#include "ircd.h" +#include "fdlist.h" +#include "s_bsd.h" +#include "conf.h" +#include "send.h" +#include "numeric.h" +#include "client.h" +#include "irc_string.h" +#include "memory.h" +#include "s_serv.h" + +/* +** init_message_file +** +*/ +void +init_message_file(MessageType msgType, const char *fileName, MessageFile *msg) +{ + strlcpy(msg->fileName, fileName, sizeof(msg->fileName)); + msg->msgType = msgType; + msg->contentsOfFile = NULL; +} + +/* +** send_message_file +** +** This function split off so a server notice could be generated on a +** user requested motd, but not on each connecting client. +*/ +int +send_message_file(struct Client *source_p, MessageFile *motdToPrint) +{ + MessageFileLine *linePointer; + MessageType msgType; + const char *from, *to; + + if (motdToPrint == NULL) + return(-1); + + msgType = motdToPrint->msgType; + + from = ID_or_name(&me, source_p->from); + to = ID_or_name(source_p, source_p->from); + + switch (msgType) + { + case USER_LINKS: + if (motdToPrint->contentsOfFile != NULL) + { + for (linePointer = motdToPrint->contentsOfFile; linePointer; + linePointer = linePointer->next) + { + sendto_one(source_p, ":%s 364 %s %s", /* XXX */ + from, to, linePointer->line); + } + } + break; + + case ISSUPPORT: + if (motdToPrint->contentsOfFile != NULL) + { + for (linePointer = motdToPrint->contentsOfFile; linePointer; + linePointer = linePointer->next) + { + sendto_one(source_p, form_str(RPL_ISUPPORT), + me.name, source_p->name, linePointer->line); + } + } + break; + + default: + break; + } + + return(0); +} + +/* + * read_message_file() - original From CoMSTuD, added Aug 29, 1996 + * + * inputs - pointer to MessageFileptr + * output - + * side effects - + */ +int +read_message_file(MessageFile *MessageFileptr) +{ + /* used to clear out old MessageFile entries */ + MessageFileLine *mptr = 0; + MessageFileLine *next_mptr = 0; + + /* used to add new MessageFile entries */ + MessageFileLine *newMessageLine = 0; + MessageFileLine *currentMessageLine = 0; + + char buffer[MESSAGELINELEN]; + char *p; + FILE *file; + + for (mptr = MessageFileptr->contentsOfFile; mptr; mptr = next_mptr) + { + next_mptr = mptr->next; + MyFree(mptr); + } + + MessageFileptr->contentsOfFile = NULL; + + if ((file = fopen(MessageFileptr->fileName, "r")) == NULL) + return(-1); + + while (fgets(buffer, sizeof(buffer), file)) + { + if ((p = strchr(buffer, '\n')) != NULL) + *p = '\0'; + + newMessageLine = (MessageFileLine *)MyMalloc(sizeof(MessageFileLine)); + strlcpy(newMessageLine->line, buffer, sizeof(newMessageLine->line)); + newMessageLine->next = NULL; + + if (MessageFileptr->contentsOfFile != NULL) + { + if (currentMessageLine) + currentMessageLine->next = newMessageLine; + + currentMessageLine = newMessageLine; + } + else + { + MessageFileptr->contentsOfFile = newMessageLine; + currentMessageLine = newMessageLine; + } + } + + fclose(file); + return(0); +} + +/* + * init_MessageLine + * + * inputs - NONE + * output - pointer to new MessageFile + * side effects - Use this when an internal Message File is wanted + * without reading an actual file. The MessageFile + * is init'ed, but must have content added to it through + * addto_MessageLine() + */ + +MessageFile * +init_MessageLine(void) +{ + MessageFile *mf; + MessageFileLine *mptr = NULL; + + mf = MyMalloc(sizeof(MessageFile)); + mf->msgType = ISSUPPORT; /* XXX maybe pass it alone in args? */ + mptr = MyMalloc(sizeof(MessageFileLine)); + mf->contentsOfFile = mptr; + return(mf); +} + +/* + * addto_MessageLine + * + * inputs - Pointer to existing MessageFile + * - New string to add to this MessageFile + * output - NONE + * side effects - Use this when an internal MessageFile is wanted + * without reading an actual file. Content is added + * to this MessageFile through this function. + */ + +void +addto_MessageLine(MessageFile *mf, const char *str) +{ + MessageFileLine *mptr = mf->contentsOfFile; + MessageFileLine *nmptr = NULL; + + if (mptr == NULL) + { + mptr = MyMalloc(sizeof(MessageFileLine)); + strcpy(mptr->line, str); + mf->contentsOfFile = mptr; + } + else + { + while (mptr->next != NULL) + mptr = mptr->next; + nmptr = MyMalloc(sizeof(MessageFileLine)); + strcpy(nmptr->line, str); + mptr->next = nmptr; + } +} + +/* + * destroy_MessageLine(MessageFile *mf) + * + * inputs - pointer to the MessageFile to destroy + * output - NONE + * side effects - All the MessageLines attached to the given mf + * Are freed then one MessageLine is recreated + */ +void +destroy_MessageLine(MessageFile *mf) +{ + MessageFileLine *mptr = mf->contentsOfFile; + MessageFileLine *nmptr = NULL; + + if (mptr == NULL) + return; + + for (mptr = mf->contentsOfFile; mptr != NULL; mptr = nmptr) + { + nmptr = mptr->next; + MyFree(mptr); + } + mf->contentsOfFile = NULL; +} @@ -1,8 +1,8 @@ /* * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). - * motd.c: Message of the day functions. * - * Copyright (C) 2002 by the past and present ircd coders, and others. + * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu> + * Copyright (C) 2013 by the Hybrid Development Team. * * 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 @@ -18,265 +18,438 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA - * - * $Id$ + */ + +/*! \file motd.c + * \brief Message-of-the-day manipulation implementation. + * \version $Id$ */ #include "stdinc.h" #include "list.h" -#include "motd.h" #include "ircd.h" -#include "fdlist.h" -#include "s_bsd.h" #include "conf.h" #include "send.h" +#include "s_serv.h" #include "numeric.h" #include "client.h" #include "irc_string.h" #include "memory.h" -#include "s_serv.h" +#include "log.h" +#include "motd.h" -/* -** init_message_file -** -*/ -void -init_message_file(MotdType motdType, const char *fileName, MessageFile *motd) + +/** Global list of messages of the day. */ +static struct +{ + struct Motd *local; /**< Local MOTD. */ + struct Motd *remote; /**< Remote MOTD. */ + dlink_list other; /**< MOTDs specified in configuration file. */ + dlink_list cachelist; /**< List of MotdCache entries. */ +} MotdList; + + +/*! \brief Create a struct Motd and initialize it. + * \param hostmask Hostmask (or connection class name) to filter on. + * \param path Path to MOTD file. + */ +static struct Motd * +motd_create(const char *hostmask, const char *path) { - strlcpy(motd->fileName, fileName, sizeof(motd->fileName)); - motd->motdType = motdType; - motd->contentsOfFile = NULL; - motd->lastChangedDate[0] = '\0'; + struct Motd *tmp = MyMalloc(sizeof(struct Motd)); + + if (EmptyString(hostmask)) + tmp->type = MOTD_UNIVERSAL; + else if (class_find(hostmask, 1)) + tmp->type = MOTD_CLASS; + else + tmp->type = MOTD_HOSTMASK; + + if (hostmask != NULL) + tmp->hostmask = xstrdup(hostmask); + + tmp->path = xstrdup(path); + tmp->maxcount = MOTD_MAXLINES; + + return tmp; } -/* -** send_message_file -** -** This function split off so a server notice could be generated on a -** user requested motd, but not on each connecting client. -*/ -int -send_message_file(struct Client *source_p, MessageFile *motdToPrint) +/*! brief\ This function reads a motd out of a file (if needed) and caches it. + * If a matching cache entry already exists, reuse it. Otherwise, + * allocate and populate a new MotdCache for it. + * \param motd Specification for MOTD file. + * \return Matching MotdCache entry. + */ +static struct MotdCache * +motd_cache(struct Motd *motd) { - MessageFileLine *linePointer; - MotdType motdType; - const char *from, *to; + FILE *file = NULL; + struct MotdCache *cache = NULL; + struct stat sb; + char line[MOTD_LINESIZE + 2]; /* \r\n */ + char *tmp = NULL; + int i; + dlink_node *ptr = NULL; + + assert(motd); + assert(motd->path); + + if (motd->cache) + return motd->cache; - if (motdToPrint == NULL) - return(-1); + /* try to find it in the list of cached files... */ + DLINK_FOREACH(ptr, MotdList.cachelist.head) + { + cache = ptr->data; + + if (!strcmp(cache->path, motd->path) && cache->maxcount == motd->maxcount) + { + cache->ref++; /* increase reference count... */ + motd->cache = cache; /* remember cache... */ + return motd->cache; /* return it */ + } + } + + /* gotta read in the file, now */ + if ((file = fopen(motd->path, "r")) == NULL) + { + ilog(LOG_TYPE_IRCD, "Couldn't open \"%s\": %s", motd->path, + strerror(errno)); + return 0; + } - motdType = motdToPrint->motdType; + /* need the file's modification time */ + if (stat(motd->path, &sb) == -1) + { + fclose(file); + return 0; + } - from = ID_or_name(&me, source_p->from); - to = ID_or_name(source_p, source_p->from); + /* Ok, allocate a structure; we'll realloc later to trim memory */ + cache = MyMalloc(sizeof(struct MotdCache) + (MOTD_LINESIZE * (MOTD_MAXLINES - 1))); + cache->ref = 1; + cache->path = xstrdup(motd->path); + cache->maxcount = motd->maxcount; + cache->modtime = *localtime((time_t *)&sb.st_mtime); /* store modtime */ - switch (motdType) + while (cache->count < cache->maxcount && fgets(line, sizeof(line), file)) { - case USER_MOTD: - if (motdToPrint->contentsOfFile == NULL) - sendto_one(source_p, form_str(ERR_NOMOTD), from, to); - else - { - sendto_one(source_p, form_str(RPL_MOTDSTART), - from, to, me.name); - - for (linePointer = motdToPrint->contentsOfFile; linePointer; - linePointer = linePointer->next) - { - sendto_one(source_p, form_str(RPL_MOTD), - from, to, linePointer->line); - } - - sendto_one(source_p, form_str(RPL_ENDOFMOTD), from, to); - } - break; - - case USER_LINKS: - if (motdToPrint->contentsOfFile != NULL) - { - for (linePointer = motdToPrint->contentsOfFile; linePointer; - linePointer = linePointer->next) - { - sendto_one(source_p, ":%s 364 %s %s", /* XXX */ - from, to, linePointer->line); - } - } - break; - - case ISSUPPORT: - if (motdToPrint->contentsOfFile != NULL) - { - for (linePointer = motdToPrint->contentsOfFile; linePointer; - linePointer = linePointer->next) - { - sendto_one(source_p, form_str(RPL_ISUPPORT), - me.name, source_p->name, linePointer->line); - } - } - break; - - default: - break; + /* copy over line, stopping when we overflow or hit line end */ + for (tmp = line, i = 0; i < (MOTD_LINESIZE - 1) && *tmp && + *tmp != '\r' && *tmp != '\n'; tmp++, i++) + cache->motd[cache->count][i] = *tmp; + cache->motd[cache->count][i] = '\0'; + + cache->count++; } - return(0); + fclose(file); /* close the file */ + + /* trim memory usage a little */ + motd->cache = MyMalloc(sizeof(struct MotdCache) + + (MOTD_LINESIZE * (cache->count - 1))); + memcpy(motd->cache, cache, sizeof(struct MotdCache) + + (MOTD_LINESIZE * (cache->count - 1))); + MyFree(cache); + + /* now link it in... */ + dlinkAdd(motd->cache, &motd->cache->node, &MotdList.cachelist); + + return motd->cache; } -/* - * read_message_file() - original From CoMSTuD, added Aug 29, 1996 - * - * inputs - pointer to MessageFileptr - * output - - * side effects - +/*! \brief Clear and dereference the Motd::cache element of \a motd. + * If the MotdCache::ref count goes to zero, free it. + * \param motd MOTD to uncache. */ -int -read_message_file(MessageFile *MessageFileptr) +static void +motd_decache(struct Motd *motd) { - struct stat sb; - struct tm *local_tm; + struct MotdCache *cache = NULL; - /* used to clear out old MessageFile entries */ - MessageFileLine *mptr = 0; - MessageFileLine *next_mptr = 0; + assert(motd); - /* used to add new MessageFile entries */ - MessageFileLine *newMessageLine = 0; - MessageFileLine *currentMessageLine = 0; + if ((cache = motd->cache) == NULL) /* we can be called for records with no cache */ + return; - char buffer[MESSAGELINELEN]; - char *p; - FILE *file; + motd->cache = NULL; /* zero the cache */ - for (mptr = MessageFileptr->contentsOfFile; mptr; mptr = next_mptr) + if (!--cache->ref) /* reduce reference count... */ { - next_mptr = mptr->next; - MyFree(mptr); + dlinkDelete(&cache->node, &MotdList.cachelist); + MyFree(cache->path); /* free path info... */ + MyFree(cache); /* very simple for a reason... */ } +} - MessageFileptr->contentsOfFile = NULL; +/*! \brief Deallocate a MOTD structure. + * If it has cached content, uncache it. + * \param motd MOTD to destroy. + */ +static void +motd_destroy(struct Motd *motd) +{ + assert(motd); - if (stat(MessageFileptr->fileName, &sb) < 0) - return(-1); + if (motd->cache) /* drop the cache */ + motd_decache(motd); - local_tm = localtime(&sb.st_mtime); + dlinkDelete(&motd->node, &MotdList.other); + MyFree(motd->path); /* we always must have a path */ + MyFree(motd->hostmask); + MyFree(motd); +} - if (local_tm) - sprintf(MessageFileptr->lastChangedDate, - "%d/%d/%d %d:%02d", - local_tm->tm_mday, - local_tm->tm_mon + 1, - 1900 + local_tm->tm_year, - local_tm->tm_hour, - local_tm->tm_min); +/*! \brief Find the first matching MOTD block for a user. + * If the user is remote, always use remote MOTD. + * Otherwise, if there is a hostmask- or class-based MOTD that matches + * the user, use it. + * Otherwise, use the local MOTD. + * \param client_p Client to find MOTD for. + * \return Pointer to first matching MOTD for the client. + */ +static struct Motd * +motd_lookup(struct Client *client_p) +{ + dlink_node *ptr = NULL; + const struct ClassItem *class = NULL; - if ((file = fopen(MessageFileptr->fileName, "r")) == NULL) - return(-1); + assert(client_p); - while (fgets(buffer, sizeof(buffer), file)) - { - if ((p = strchr(buffer, '\n')) != NULL) - *p = '\0'; + if (!MyClient(client_p)) /* not my user, always return remote motd */ + return MotdList.remote; - newMessageLine = (MessageFileLine *)MyMalloc(sizeof(MessageFileLine)); - strlcpy(newMessageLine->line, buffer, sizeof(newMessageLine->line)); - newMessageLine->next = NULL; + class = get_class_ptr(&client_p->localClient->confs); + assert(class); - if (MessageFileptr->contentsOfFile != NULL) - { - if (currentMessageLine) - currentMessageLine->next = newMessageLine; + /* check the motd blocks first */ + DLINK_FOREACH(ptr, MotdList.other.head) + { + struct Motd *motd = ptr->data; - currentMessageLine = newMessageLine; - } - else + switch (motd->type) { - MessageFileptr->contentsOfFile = newMessageLine; - currentMessageLine = newMessageLine; + case MOTD_CLASS: + if (!match(motd->hostmask, class->name)) + return motd; + case MOTD_HOSTMASK: + if (!match(motd->hostmask, client_p->host)) + return motd; + default: break; } } - fclose(file); - return(0); + return MotdList.local; /* Ok, return the default motd */ } -/* - * init_MessageLine - * - * inputs - NONE - * output - pointer to new MessageFile - * side effects - Use this when an internal Message File is wanted - * without reading an actual file. The MessageFile - * is init'ed, but must have content added to it through - * addto_MessageLine() +/*! \brief Send the content of a MotdCache to a user. + * If \a cache is NULL, simply send ERR_NOMOTD to the client. + * \param source_p Client to send MOTD to. + * \param cache MOTD body to send to client. */ - -MessageFile * -init_MessageLine(void) +static void +motd_forward(struct Client *source_p, const struct MotdCache *cache) { - MessageFile *mf; - MessageFileLine *mptr = NULL; - - mf = MyMalloc(sizeof(MessageFile)); - mf->motdType = ISSUPPORT; /* XXX maybe pass it alone in args? */ - mptr = MyMalloc(sizeof(MessageFileLine)); - mf->contentsOfFile = mptr; - return(mf); + int i; + const char *from = ID_or_name(&me, source_p->from); + const char *to = ID_or_name(source_p, source_p->from); + + assert(source_p); + + if (!cache) /* no motd to send */ + { + sendto_one(source_p, form_str(ERR_NOMOTD), from, to); + return; + } + + /* send the motd */ + sendto_one(source_p, form_str(RPL_MOTDSTART), + from, to, me.name); + + for (i = 0; i < cache->count; i++) + sendto_one(source_p, form_str(RPL_MOTD), + from, to, cache->motd[i]); + sendto_one(source_p, form_str(RPL_ENDOFMOTD), from, to); } -/* - * addto_MessageLine - * - * inputs - Pointer to existing MessageFile - * - New string to add to this MessageFile - * output - NONE - * side effects - Use this when an internal MessageFile is wanted - * without reading an actual file. Content is added - * to this MessageFile through this function. +/*! \brief Find the MOTD for a client and send it. + * \param client_p Client being greeted. */ +void +motd_send(struct Client *client_p) +{ + assert(client_p); + motd_forward(client_p, motd_cache(motd_lookup(client_p))); +} + +/*! \brief Send the signon MOTD to a user. + * If FEAT_NODEFAULTMOTD is true and a matching MOTD exists for the + * user, direct the client to type /MOTD to read it. Otherwise, call + * motd_forward() for the user. + * \param source_p Client that has just connected. + */ void -addto_MessageLine(MessageFile *mf, const char *str) +motd_signon(struct Client *source_p) { - MessageFileLine *mptr = mf->contentsOfFile; - MessageFileLine *nmptr = NULL; + const struct MotdCache *cache = motd_cache(motd_lookup(source_p)); - if (mptr == NULL) + if (!ConfigFileEntry.short_motd || !cache) + motd_forward(source_p, cache); + else { - mptr = MyMalloc(sizeof(MessageFileLine)); - strcpy(mptr->line, str); - mf->contentsOfFile = mptr; + sendto_one(source_p, ":%s NOTICE %s :*** Notice -- motd was last changed at %d/%d/%d %d:%02d", + me.name, source_p->name, cache->modtime.tm_year + 1900, + cache->modtime.tm_mon + 1, + cache->modtime.tm_mday, + cache->modtime.tm_hour, + cache->modtime.tm_min); + sendto_one(source_p, + ":%s NOTICE %s :*** Notice -- Please read the motd if you haven't " + "read it", me.name, source_p->name); + sendto_one(source_p, form_str(RPL_MOTDSTART), + me.name, source_p->name, me.name); + sendto_one(source_p, form_str(RPL_MOTD), + me.name, source_p->name, + "*** This is the short motd ***"); + sendto_one(source_p, form_str(RPL_ENDOFMOTD), + me.name, source_p->name); } - else +} + +/*! \brief Clear all cached MOTD bodies. + * The local and remote MOTDs are re-cached immediately. + */ +void +motd_recache(void) +{ + dlink_node *ptr = NULL; + + motd_decache(MotdList.local); /* decache local and remote MOTDs */ + motd_decache(MotdList.remote); + + DLINK_FOREACH(ptr, MotdList.other.head) /* now all the others */ + motd_decache(ptr->data); + + /* now recache local and remote MOTDs */ + motd_cache(MotdList.local); + motd_cache(MotdList.remote); +} + +/*! \brief Re-cache the local and remote MOTDs. + * If they already exist, they are deallocated first. + */ +void +motd_init(void) +{ + if (MotdList.local) /* destroy old local... */ + motd_destroy(MotdList.local); + + MotdList.local = motd_create(0, MPATH); + motd_cache(MotdList.local); /* init local and cache it */ + + if (MotdList.remote) /* destroy old remote... */ + motd_destroy(MotdList.remote); + + MotdList.remote = motd_create(0, MPATH); + motd_cache(MotdList.remote); /* init remote and cache it */ +} + +/* \brief Add a new MOTD. + * \param hostmask Hostmask (or connection class name) to send this to. + * \param path Pathname of file to send. + */ +void +motd_add(const char *hostmask, const char *path) +{ + struct Motd *motd = motd_create(hostmask, path); /* create the motd */ + + dlinkAdd(motd, &motd->node, &MotdList.other); +} + +/*! \brief Clear out all MOTDs. + * Compared to motd_recache(), this destroys all hostmask- or + * class-based MOTDs rather than simply uncaching them. + * Re-cache the local and remote MOTDs. + */ +void +motd_clear(void) +{ + dlink_node *ptr = NULL, *ptr_next = NULL; + + motd_decache(MotdList.local); /* decache local and remote MOTDs */ + motd_decache(MotdList.remote); + + DLINK_FOREACH_SAFE(ptr, ptr_next, MotdList.other.head) /* destroy other MOTDs */ + motd_destroy(ptr->data); + + /* now recache local and remote MOTDs */ + motd_cache(MotdList.local); + motd_cache(MotdList.remote); +} + +/*! \brief Report list of non-default MOTDs. + * \param source_p Client requesting statistics. + */ +void +motd_report(struct Client *source_p) +{ + const dlink_node *ptr = NULL; + + DLINK_FOREACH(ptr, MotdList.other.head) { - while (mptr->next != NULL) - mptr = mptr->next; - nmptr = MyMalloc(sizeof(MessageFileLine)); - strcpy(nmptr->line, str); - mptr->next = nmptr; + const struct Motd *motd = ptr->data; + + sendto_one(source_p, form_str(RPL_STATSTLINE), + me.name, source_p->name, + motd->hostmask, motd->path); } } -/* - * destroy_MessageLine(MessageFile *mf) - * - * inputs - pointer to the MessageFile to destroy - * output - NONE - * side effects - All the MessageLines attached to the given mf - * Are freed then one MessageLine is recreated +/*! \brief Report MOTD memory usage to a client. + * \param source_p Client requesting memory usage. */ void -destroy_MessageLine(MessageFile *mf) +motd_memory_count(struct Client *source_p) { - MessageFileLine *mptr = mf->contentsOfFile; - MessageFileLine *nmptr = NULL; + const dlink_node *ptr = NULL; + unsigned int mt = 0; /* motd count */ + unsigned int mtc = 0; /* motd cache count */ + size_t mtm = 0; /* memory consumed by motd */ + size_t mtcm = 0; /* memory consumed by motd cache */ - if (mptr == NULL) - return; + if (MotdList.local) + { + mt++; + mtm += sizeof(struct Motd); + mtm += MotdList.local->path ? (strlen(MotdList.local->path) + 1) : 0; + } + + if (MotdList.remote) + { + mt++; + mtm += sizeof(struct Motd); + mtm += MotdList.remote->path ? (strlen(MotdList.remote->path) + 1) : 0; + } - for (mptr = mf->contentsOfFile; mptr != NULL; mptr = nmptr) + DLINK_FOREACH(ptr, MotdList.other.head) { - nmptr = mptr->next; - MyFree(mptr); - } - mf->contentsOfFile = NULL; + const struct MotdCache *motd = ptr->data; + + mt++; + mtm += sizeof(struct Motd); + mtm += motd->path ? (strlen(motd->path) + 1) : 0; + } + + DLINK_FOREACH(ptr, MotdList.cachelist.head) + { + const struct MotdCache *cache = ptr->data; + + mtc++; + mtcm += sizeof(struct MotdCache) + (MOTD_LINESIZE * (cache->count - 1)); + } + + sendto_one(source_p, ":%s %d %s z :Motds %u(%u) Cache %u(%u)", + me.name, RPL_STATSDEBUG, source_p->name, + mt, mtm, mtc, mtcm); } diff --git a/src/numeric.c b/src/numeric.c index 17d7656..857d185 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -272,7 +272,7 @@ static const char *replies[] = { /* 242 RPL_STATSUPTIME */ ":%s 242 %s :Server Up %d days, %d:%02d:%02d", /* 243 RPL_STATSOLINE */ ":%s 243 %s %c %u %s@%s * %s %s %s", /* 244 RPL_STATSHLINE */ ":%s 244 %s %c %s * %s %d %s", -/* 245 */ NULL, +/* 245 RPL_STATSTLINE */ ":%s 245 %s T %s %s", /* 246 RPL_STATSSERVICE */ ":%s 246 %s %c %s * %s %d %d", /* 247 RPL_STATSXLINE */ ":%s 247 %s %c %d %s :%s", /* 248 RPL_STATSULINE */ ":%s 248 %s U %s %s@%s %s", diff --git a/src/s_user.c b/src/s_user.c index 095100e..e480da3 100644 --- a/src/s_user.c +++ b/src/s_user.c @@ -51,7 +51,7 @@ #include "s_misc.h" #include "parse.h" #include "watch.h" - +#include "message.h" static char umode_buffer[IRCD_BUFSIZE]; @@ -1171,24 +1171,7 @@ user_welcome(struct Client *source_p) source_p->name, source_p->id); show_lusers(source_p); - - if (ConfigFileEntry.short_motd) - { - sendto_one(source_p, ":%s NOTICE %s :*** Notice -- motd was last changed at %s", - me.name, source_p->name, ConfigFileEntry.motd.lastChangedDate); - sendto_one(source_p, - ":%s NOTICE %s :*** Notice -- Please read the motd if you haven't " - "read it", me.name, source_p->name); - sendto_one(source_p, form_str(RPL_MOTDSTART), - me.name, source_p->name, me.name); - sendto_one(source_p, form_str(RPL_MOTD), - me.name, source_p->name, - "*** This is the short motd ***"); - sendto_one(source_p, form_str(RPL_ENDOFMOTD), - me.name, source_p->name); - } - else - send_message_file(source_p, &ConfigFileEntry.motd); + motd_signon(source_p); } /* check_xline() |