ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/motd.c
Revision: 3109
Committed: Thu Mar 6 19:25:12 2014 UTC (11 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 13101 byte(s)
Log Message:
- Applied Adam's sendto_one_numeric() changes

File Contents

# User Rev Content
1 adx 30 /*
2 michael 2916 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 adx 30 *
4 michael 2916 * Copyright (c) 2000 Kevin L. Mitchell <klmitch@mit.edu>
5     * Copyright (c) 2013-2014 ircd-hybrid development team
6 adx 30 *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20     * USA
21     */
22    
23 michael 2150 /*! \file motd.c
24     * \brief Message-of-the-day manipulation implementation.
25     * \version $Id$
26     */
27    
28 adx 30 #include "stdinc.h"
29 michael 1011 #include "list.h"
30 adx 30 #include "ircd.h"
31 michael 1309 #include "conf.h"
32 adx 30 #include "send.h"
33 michael 2150 #include "s_serv.h"
34 adx 30 #include "numeric.h"
35     #include "client.h"
36     #include "irc_string.h"
37     #include "memory.h"
38 michael 2150 #include "log.h"
39     #include "motd.h"
40 michael 2167 #include "hostmask.h"
41 adx 30
42 michael 2150
43     /** Global list of messages of the day. */
44     static struct
45 adx 30 {
46 michael 2150 struct Motd *local; /**< Local MOTD. */
47     struct Motd *remote; /**< Remote MOTD. */
48     dlink_list other; /**< MOTDs specified in configuration file. */
49     dlink_list cachelist; /**< List of MotdCache entries. */
50     } MotdList;
51    
52    
53     /*! \brief Create a struct Motd and initialize it.
54     * \param hostmask Hostmask (or connection class name) to filter on.
55     * \param path Path to MOTD file.
56     */
57     static struct Motd *
58     motd_create(const char *hostmask, const char *path)
59     {
60     struct Motd *tmp = MyMalloc(sizeof(struct Motd));
61    
62     if (EmptyString(hostmask))
63     tmp->type = MOTD_UNIVERSAL;
64     else if (class_find(hostmask, 1))
65     tmp->type = MOTD_CLASS;
66     else
67 michael 2167 {
68     switch (parse_netmask(hostmask, &tmp->address, &tmp->addrbits))
69     {
70     case HM_IPV4:
71     tmp->type = MOTD_IPMASKV4;
72     break;
73     #ifdef IPV6
74     case HM_IPV6:
75     tmp->type = MOTD_IPMASKV6;
76     break;
77     #endif
78     default: /* HM_HOST */
79     tmp->type = MOTD_HOSTMASK;
80     break;
81     }
82     }
83 michael 2150
84     if (hostmask != NULL)
85     tmp->hostmask = xstrdup(hostmask);
86    
87     tmp->path = xstrdup(path);
88     tmp->maxcount = MOTD_MAXLINES;
89    
90     return tmp;
91 adx 30 }
92    
93 michael 2150 /*! brief\ This function reads a motd out of a file (if needed) and caches it.
94     * If a matching cache entry already exists, reuse it. Otherwise,
95     * allocate and populate a new MotdCache for it.
96     * \param motd Specification for MOTD file.
97     * \return Matching MotdCache entry.
98     */
99     static struct MotdCache *
100     motd_cache(struct Motd *motd)
101 adx 30 {
102 michael 2150 FILE *file = NULL;
103     struct MotdCache *cache = NULL;
104     struct stat sb;
105     char line[MOTD_LINESIZE + 2]; /* \r\n */
106 michael 2194 char *tmp = NULL;
107 michael 2164 unsigned int i = 0;
108 michael 2150 dlink_node *ptr = NULL;
109 adx 30
110 michael 2150 assert(motd);
111     assert(motd->path);
112 adx 30
113 michael 2150 if (motd->cache)
114     return motd->cache;
115 adx 30
116 michael 2150 /* try to find it in the list of cached files... */
117     DLINK_FOREACH(ptr, MotdList.cachelist.head)
118     {
119     cache = ptr->data;
120 adx 30
121 michael 2150 if (!strcmp(cache->path, motd->path) && cache->maxcount == motd->maxcount)
122     {
123     cache->ref++; /* increase reference count... */
124     motd->cache = cache; /* remember cache... */
125     return motd->cache; /* return it */
126     }
127     }
128    
129 michael 2190 /* need the file's modification time */
130     if (stat(motd->path, &sb) == -1)
131 adx 30 {
132 michael 2190 ilog(LOG_TYPE_IRCD, "Couldn't stat \"%s\": %s", motd->path,
133 michael 2150 strerror(errno));
134     return 0;
135     }
136 adx 30
137 michael 2190 /* gotta read in the file, now */
138     if ((file = fopen(motd->path, "r")) == NULL)
139 michael 2150 {
140 michael 2190 ilog(LOG_TYPE_IRCD, "Couldn't open \"%s\": %s", motd->path,
141     strerror(errno));
142 michael 2150 return 0;
143     }
144 adx 30
145 michael 2150 /* Ok, allocate a structure; we'll realloc later to trim memory */
146 michael 2410 cache = MyMalloc(sizeof(struct MotdCache) + (MOTD_LINESIZE * MOTD_MAXLINES));
147 michael 2150 cache->ref = 1;
148     cache->path = xstrdup(motd->path);
149     cache->maxcount = motd->maxcount;
150     cache->modtime = *localtime((time_t *)&sb.st_mtime); /* store modtime */
151 adx 30
152 michael 2150 while (cache->count < cache->maxcount && fgets(line, sizeof(line), file))
153     {
154     /* copy over line, stopping when we overflow or hit line end */
155 michael 2194 for (tmp = line, i = 0; i < (MOTD_LINESIZE - 1) && *tmp && *tmp != '\r' && *tmp != '\n'; ++tmp, ++i)
156 michael 2150 cache->motd[cache->count][i] = *tmp;
157     cache->motd[cache->count][i] = '\0';
158 adx 30
159 michael 2150 cache->count++;
160 adx 30 }
161    
162 michael 2150 fclose(file); /* close the file */
163    
164     /* trim memory usage a little */
165     motd->cache = MyMalloc(sizeof(struct MotdCache) +
166 michael 2410 (MOTD_LINESIZE * cache->count));
167 michael 2150 memcpy(motd->cache, cache, sizeof(struct MotdCache) +
168 michael 2410 (MOTD_LINESIZE * cache->count));
169 michael 2150 MyFree(cache);
170    
171     /* now link it in... */
172     dlinkAdd(motd->cache, &motd->cache->node, &MotdList.cachelist);
173    
174     return motd->cache;
175 adx 30 }
176    
177 michael 2150 /*! \brief Clear and dereference the Motd::cache element of \a motd.
178     * If the MotdCache::ref count goes to zero, free it.
179     * \param motd MOTD to uncache.
180 adx 30 */
181 michael 2150 static void
182     motd_decache(struct Motd *motd)
183 adx 30 {
184 michael 2150 struct MotdCache *cache = NULL;
185 adx 30
186 michael 2150 assert(motd);
187 adx 30
188 michael 2150 if ((cache = motd->cache) == NULL) /* we can be called for records with no cache */
189     return;
190 adx 30
191 michael 2150 motd->cache = NULL; /* zero the cache */
192 adx 30
193 michael 2164 if (--cache->ref == 0) /* reduce reference count... */
194 adx 30 {
195 michael 2150 dlinkDelete(&cache->node, &MotdList.cachelist);
196     MyFree(cache->path); /* free path info... */
197     MyFree(cache); /* very simple for a reason... */
198 adx 30 }
199 michael 2150 }
200 adx 30
201 michael 2150 /*! \brief Deallocate a MOTD structure.
202     * If it has cached content, uncache it.
203     * \param motd MOTD to destroy.
204     */
205     static void
206     motd_destroy(struct Motd *motd)
207     {
208     assert(motd);
209 adx 30
210 michael 2150 if (motd->cache) /* drop the cache */
211     motd_decache(motd);
212 adx 30
213 michael 2150 MyFree(motd->path); /* we always must have a path */
214     MyFree(motd->hostmask);
215     MyFree(motd);
216     }
217 adx 30
218 michael 2150 /*! \brief Find the first matching MOTD block for a user.
219     * If the user is remote, always use remote MOTD.
220     * Otherwise, if there is a hostmask- or class-based MOTD that matches
221     * the user, use it.
222     * Otherwise, use the local MOTD.
223     * \param client_p Client to find MOTD for.
224     * \return Pointer to first matching MOTD for the client.
225     */
226     static struct Motd *
227 michael 2874 motd_lookup(const struct Client *client_p)
228 michael 2150 {
229     dlink_node *ptr = NULL;
230     const struct ClassItem *class = NULL;
231 adx 30
232 michael 2150 assert(client_p);
233 adx 30
234 michael 2150 if (!MyClient(client_p)) /* not my user, always return remote motd */
235     return MotdList.remote;
236 adx 30
237 michael 2150 class = get_class_ptr(&client_p->localClient->confs);
238     assert(class);
239 adx 30
240 michael 2150 /* check the motd blocks first */
241     DLINK_FOREACH(ptr, MotdList.other.head)
242     {
243     struct Motd *motd = ptr->data;
244 adx 30
245 michael 2150 switch (motd->type)
246 adx 30 {
247 michael 2150 case MOTD_CLASS:
248     if (!match(motd->hostmask, class->name))
249     return motd;
250 michael 2167 break;
251 michael 2150 case MOTD_HOSTMASK:
252     if (!match(motd->hostmask, client_p->host))
253     return motd;
254 michael 2167 break;
255     case MOTD_IPMASKV4:
256     if (client_p->localClient->aftype == AF_INET)
257     if (match_ipv4(&client_p->localClient->ip, &motd->address, motd->addrbits))
258     return motd;
259     break;
260 michael 2168 #ifdef IPV6
261 michael 2167 case MOTD_IPMASKV6:
262     if (client_p->localClient->aftype == AF_INET6)
263     if (match_ipv6(&client_p->localClient->ip, &motd->address, motd->addrbits))
264     return motd;
265     break;
266 michael 2168 #endif
267 michael 2150 default: break;
268 adx 30 }
269     }
270    
271 michael 2150 return MotdList.local; /* Ok, return the default motd */
272 adx 30 }
273    
274 michael 2150 /*! \brief Send the content of a MotdCache to a user.
275     * If \a cache is NULL, simply send ERR_NOMOTD to the client.
276     * \param source_p Client to send MOTD to.
277     * \param cache MOTD body to send to client.
278 adx 30 */
279 michael 2150 static void
280     motd_forward(struct Client *source_p, const struct MotdCache *cache)
281     {
282 michael 2164 unsigned int i = 0;
283 adx 30
284 michael 2150 assert(source_p);
285    
286     if (!cache) /* no motd to send */
287     {
288 michael 3109 sendto_one_numeric(source_p, &me, ERR_NOMOTD);
289 michael 2150 return;
290     }
291    
292     /* send the motd */
293 michael 3109 sendto_one_numeric(source_p, &me, RPL_MOTDSTART, me.name);
294 michael 2150
295 michael 2164 for (; i < cache->count; ++i)
296 michael 3109 sendto_one_numeric(source_p, &me, RPL_MOTD, cache->motd[i]);
297     sendto_one_numeric(source_p, &me, RPL_ENDOFMOTD);
298 michael 2150 }
299    
300     /*! \brief Find the MOTD for a client and send it.
301     * \param client_p Client being greeted.
302     */
303     void
304     motd_send(struct Client *client_p)
305 adx 30 {
306 michael 2150 assert(client_p);
307 adx 30
308 michael 2150 motd_forward(client_p, motd_cache(motd_lookup(client_p)));
309 adx 30 }
310    
311 michael 2150 /*! \brief Send the signon MOTD to a user.
312     * If FEAT_NODEFAULTMOTD is true and a matching MOTD exists for the
313     * user, direct the client to type /MOTD to read it. Otherwise, call
314     * motd_forward() for the user.
315     * \param source_p Client that has just connected.
316 adx 30 */
317     void
318 michael 2150 motd_signon(struct Client *source_p)
319 adx 30 {
320 michael 2150 const struct MotdCache *cache = motd_cache(motd_lookup(source_p));
321 adx 30
322 michael 2150 if (!ConfigFileEntry.short_motd || !cache)
323     motd_forward(source_p, cache);
324     else
325 adx 30 {
326 michael 2150 sendto_one(source_p, ":%s NOTICE %s :*** Notice -- motd was last changed at %d/%d/%d %d:%02d",
327     me.name, source_p->name, cache->modtime.tm_year + 1900,
328     cache->modtime.tm_mon + 1,
329     cache->modtime.tm_mday,
330     cache->modtime.tm_hour,
331     cache->modtime.tm_min);
332     sendto_one(source_p,
333     ":%s NOTICE %s :*** Notice -- Please read the motd if you haven't "
334     "read it", me.name, source_p->name);
335 michael 3109
336     sendto_one_numeric(source_p, &me, RPL_MOTDSTART, me.name);
337     sendto_one_numeric(source_p, &me, RPL_MOTD,
338     "*** This is the short motd ***");
339     sendto_one_numeric(source_p, &me, RPL_ENDOFMOTD);
340 adx 30 }
341 michael 2150 }
342    
343     /*! \brief Clear all cached MOTD bodies.
344     * The local and remote MOTDs are re-cached immediately.
345     */
346     void
347     motd_recache(void)
348     {
349     dlink_node *ptr = NULL;
350    
351     motd_decache(MotdList.local); /* decache local and remote MOTDs */
352     motd_decache(MotdList.remote);
353    
354     DLINK_FOREACH(ptr, MotdList.other.head) /* now all the others */
355     motd_decache(ptr->data);
356    
357     /* now recache local and remote MOTDs */
358     motd_cache(MotdList.local);
359     motd_cache(MotdList.remote);
360     }
361    
362     /*! \brief Re-cache the local and remote MOTDs.
363     * If they already exist, they are deallocated first.
364     */
365     void
366     motd_init(void)
367     {
368     if (MotdList.local) /* destroy old local... */
369     motd_destroy(MotdList.local);
370    
371 michael 2203 MotdList.local = motd_create(NULL, MPATH);
372 michael 2150 motd_cache(MotdList.local); /* init local and cache it */
373    
374     if (MotdList.remote) /* destroy old remote... */
375     motd_destroy(MotdList.remote);
376    
377 michael 2203 MotdList.remote = motd_create(NULL, MPATH);
378 michael 2150 motd_cache(MotdList.remote); /* init remote and cache it */
379     }
380    
381     /* \brief Add a new MOTD.
382     * \param hostmask Hostmask (or connection class name) to send this to.
383     * \param path Pathname of file to send.
384     */
385     void
386     motd_add(const char *hostmask, const char *path)
387     {
388     struct Motd *motd = motd_create(hostmask, path); /* create the motd */
389    
390     dlinkAdd(motd, &motd->node, &MotdList.other);
391     }
392    
393     /*! \brief Clear out all MOTDs.
394     * Compared to motd_recache(), this destroys all hostmask- or
395     * class-based MOTDs rather than simply uncaching them.
396     * Re-cache the local and remote MOTDs.
397     */
398     void
399     motd_clear(void)
400     {
401     dlink_node *ptr = NULL, *ptr_next = NULL;
402    
403     motd_decache(MotdList.local); /* decache local and remote MOTDs */
404     motd_decache(MotdList.remote);
405    
406     DLINK_FOREACH_SAFE(ptr, ptr_next, MotdList.other.head) /* destroy other MOTDs */
407 michael 2193 {
408     dlinkDelete(ptr, &MotdList.other);
409 michael 2150 motd_destroy(ptr->data);
410 michael 2193 }
411 michael 2150
412     /* now recache local and remote MOTDs */
413     motd_cache(MotdList.local);
414     motd_cache(MotdList.remote);
415     }
416    
417     /*! \brief Report list of non-default MOTDs.
418     * \param source_p Client requesting statistics.
419     */
420     void
421     motd_report(struct Client *source_p)
422     {
423     const dlink_node *ptr = NULL;
424    
425     DLINK_FOREACH(ptr, MotdList.other.head)
426 adx 30 {
427 michael 2150 const struct Motd *motd = ptr->data;
428    
429 michael 3109 sendto_one_numeric(source_p, &me, RPL_STATSTLINE,
430     motd->hostmask, motd->path);
431 adx 30 }
432     }
433    
434 michael 2150 /*! \brief Report MOTD memory usage to a client.
435     * \param source_p Client requesting memory usage.
436 adx 30 */
437     void
438 michael 2150 motd_memory_count(struct Client *source_p)
439 adx 30 {
440 michael 2150 const dlink_node *ptr = NULL;
441     unsigned int mt = 0; /* motd count */
442     unsigned int mtc = 0; /* motd cache count */
443     size_t mtm = 0; /* memory consumed by motd */
444     size_t mtcm = 0; /* memory consumed by motd cache */
445 adx 30
446 michael 2150 if (MotdList.local)
447     {
448     mt++;
449     mtm += sizeof(struct Motd);
450     mtm += MotdList.local->path ? (strlen(MotdList.local->path) + 1) : 0;
451     }
452 adx 30
453 michael 2150 if (MotdList.remote)
454 adx 30 {
455 michael 2150 mt++;
456     mtm += sizeof(struct Motd);
457     mtm += MotdList.remote->path ? (strlen(MotdList.remote->path) + 1) : 0;
458     }
459    
460     DLINK_FOREACH(ptr, MotdList.other.head)
461     {
462 michael 2320 const struct Motd *motd = ptr->data;
463 michael 2150
464     mt++;
465     mtm += sizeof(struct Motd);
466     mtm += motd->path ? (strlen(motd->path) + 1) : 0;
467     }
468    
469     DLINK_FOREACH(ptr, MotdList.cachelist.head)
470     {
471     const struct MotdCache *cache = ptr->data;
472    
473     mtc++;
474     mtcm += sizeof(struct MotdCache) + (MOTD_LINESIZE * (cache->count - 1));
475     }
476    
477     sendto_one(source_p, ":%s %d %s z :Motds %u(%u) Cache %u(%u)",
478     me.name, RPL_STATSDEBUG, source_p->name,
479     mt, mtm, mtc, mtcm);
480 adx 30 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision