ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/motd.c
Revision: 2164
Committed: Sun Jun 2 19:42:58 2013 UTC (12 years, 2 months ago) by michael
Content type: text/x-csrc
File size: 12528 byte(s)
Log Message:
- motd.h, motd.c: minor cleanups. use 'unsigned' whenever possible

File Contents

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

Properties

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