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

Properties

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