ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/motd.c
Revision: 3504
Committed: Sat May 10 19:51:29 2014 UTC (11 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 13011 byte(s)
Log Message:
- Renamed MyMalloc() to MyCalloc()

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

Properties

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