2 * ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
3 * cache.c - code for caching files
5 * Copyright (C) 2003 Lee Hardy <lee@leeh.co.uk>
6 * Copyright (C) 2003-2005 ircd-ratbox development team
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * 1.Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * 2.Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3.The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 #include "ircd_defs.h"
39 #include "rb_dictionary.h"
43 struct cachefile
*user_motd
= NULL
;
44 struct cachefile
*oper_motd
= NULL
;
45 struct cacheline
*emptyline
= NULL
;
46 rb_dlink_list links_cache_list
;
47 char user_motd_changed
[MAX_DATE_STRING
];
49 rb_dictionary
*help_dict_oper
= NULL
;
50 rb_dictionary
*help_dict_user
= NULL
;
56 * side effects - inits the file/line cache blockheaps, loads motds
61 /* allocate the emptyline */
62 emptyline
= rb_malloc(sizeof(struct cacheline
));
63 emptyline
->data
= rb_strdup(" ");
65 user_motd_changed
[0] = '\0';
67 user_motd
= cache_file(ircd_paths
[IRCD_PATH_IRCD_MOTD
], "ircd.motd", 0);
68 oper_motd
= cache_file(ircd_paths
[IRCD_PATH_IRCD_OMOTD
], "opers.motd", 0);
69 memset(&links_cache_list
, 0, sizeof(links_cache_list
));
71 help_dict_oper
= rb_dictionary_create("oper help", rb_strcasecmp
);
72 help_dict_user
= rb_dictionary_create("user help", rb_strcasecmp
);
76 * removes tabs from src, replaces with 8 spaces, and returns the length
77 * of the new string. if the new string would be greater than destlen,
78 * it is truncated to destlen - 1
81 untabify(char *dest
, const char *src
, size_t destlen
)
87 while(*s
!= '\0' && x
< destlen
- 1)
91 for(i
= 0; i
< 8 && x
< destlen
- 1; i
++, x
++, d
++)
106 * inputs - file to cache, files "shortname", flags to set
107 * outputs - pointer to file cached, else NULL
111 cache_file(const char *filename
, const char *shortname
, int flags
)
114 struct cachefile
*cacheptr
;
115 struct cacheline
*lineptr
;
119 if((in
= fopen(filename
, "r")) == NULL
)
123 cacheptr
= rb_malloc(sizeof(struct cachefile
));
125 rb_strlcpy(cacheptr
->name
, shortname
, sizeof(cacheptr
->name
));
126 cacheptr
->flags
= flags
;
128 /* cache the file... */
129 while(fgets(line
, sizeof(line
), in
) != NULL
)
131 if((p
= strpbrk(line
, "\r\n")) != NULL
)
134 if(!EmptyString(line
))
136 char untabline
[BUFSIZE
];
138 lineptr
= rb_malloc(sizeof(struct cacheline
));
140 untabify(untabline
, line
, sizeof(untabline
));
141 lineptr
->data
= rb_strdup(untabline
);
143 rb_dlinkAddTail(lineptr
, &lineptr
->linenode
, &cacheptr
->contents
);
146 rb_dlinkAddTailAlloc(emptyline
, &cacheptr
->contents
);
149 if (0 == rb_dlink_list_length(&cacheptr
->contents
))
151 /* No contents. Don't cache it after all. */
161 cache_links(void *unused
)
163 struct Client
*target_p
;
165 rb_dlink_node
*next_ptr
;
168 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, links_cache_list
.head
)
171 rb_free_rb_dlink_node(ptr
);
174 links_cache_list
.head
= links_cache_list
.tail
= NULL
;
175 links_cache_list
.length
= 0;
177 RB_DLINK_FOREACH(ptr
, global_serv_list
.head
)
179 target_p
= ptr
->data
;
181 /* skip ourselves (done in /links) and hidden servers */
183 (IsHidden(target_p
) && !ConfigServerHide
.disable_hidden
))
186 /* if the below is ever modified, change LINKSLINELEN */
187 links_line
= rb_malloc(LINKSLINELEN
);
188 snprintf(links_line
, LINKSLINELEN
, "%s %s :1 %s",
189 target_p
->name
, me
.name
,
190 target_p
->info
[0] ? target_p
->info
:
191 "(Unknown Location)");
193 rb_dlinkAddTailAlloc(links_line
, &links_cache_list
);
199 * inputs - cachefile to free
201 * side effects - cachefile and its data is free'd
204 free_cachefile(struct cachefile
*cacheptr
)
207 rb_dlink_node
*next_ptr
;
212 RB_DLINK_FOREACH_SAFE(ptr
, next_ptr
, cacheptr
->contents
.head
)
214 if(ptr
->data
!= emptyline
)
216 struct cacheline
*line
= ptr
->data
;
222 rb_free_rb_dlink_node(ptr
);
233 * side effects - old help cache deleted
234 * - contents of help directories are loaded.
239 DIR *helpfile_dir
= NULL
;
240 struct dirent
*ldirent
= NULL
;
241 char filename
[PATH_MAX
];
242 struct cachefile
*cacheptr
;
243 rb_dictionary_iter iter
;
245 #if defined(S_ISLNK) && defined(HAVE_LSTAT)
249 RB_DICTIONARY_FOREACH(cacheptr
, &iter
, help_dict_oper
)
251 rb_dictionary_delete(help_dict_oper
, cacheptr
->name
);
252 free_cachefile(cacheptr
);
254 RB_DICTIONARY_FOREACH(cacheptr
, &iter
, help_dict_user
)
256 rb_dictionary_delete(help_dict_user
, cacheptr
->name
);
257 free_cachefile(cacheptr
);
260 helpfile_dir
= opendir(ircd_paths
[IRCD_PATH_OPERHELP
]);
262 if(helpfile_dir
== NULL
)
265 while((ldirent
= readdir(helpfile_dir
)) != NULL
)
267 if(ldirent
->d_name
[0] == '.')
269 snprintf(filename
, sizeof(filename
), "%s%c%s", ircd_paths
[IRCD_PATH_OPERHELP
], RB_PATH_SEPARATOR
, ldirent
->d_name
);
270 cacheptr
= cache_file(filename
, ldirent
->d_name
, HELP_OPER
);
271 rb_dictionary_add(help_dict_oper
, cacheptr
->name
, cacheptr
);
274 closedir(helpfile_dir
);
275 helpfile_dir
= opendir(ircd_paths
[IRCD_PATH_USERHELP
]);
277 if(helpfile_dir
== NULL
)
280 while((ldirent
= readdir(helpfile_dir
)) != NULL
)
282 if(ldirent
->d_name
[0] == '.')
284 snprintf(filename
, sizeof(filename
), "%s%c%s", ircd_paths
[IRCD_PATH_USERHELP
], RB_PATH_SEPARATOR
, ldirent
->d_name
);
286 #if defined(S_ISLNK) && defined(HAVE_LSTAT)
287 if(lstat(filename
, &sb
) < 0)
290 /* ok, if its a symlink, we work on the presumption if an
291 * oper help exists of that name, its a symlink to that --fl
293 if(S_ISLNK(sb
.st_mode
))
295 cacheptr
= rb_dictionary_retrieve(help_dict_oper
, ldirent
->d_name
);
299 cacheptr
->flags
|= HELP_USER
;
305 cacheptr
= cache_file(filename
, ldirent
->d_name
, HELP_USER
);
306 rb_dictionary_add(help_dict_user
, cacheptr
->name
, cacheptr
);
309 closedir(helpfile_dir
);
314 * inputs - client to send motd to
315 * outputs - client is sent motd if exists, else ERR_NOMOTD
319 send_user_motd(struct Client
*source_p
)
321 struct cacheline
*lineptr
;
323 const char *myname
= get_id(&me
, source_p
);
324 const char *nick
= get_id(source_p
, source_p
);
325 if(user_motd
== NULL
|| rb_dlink_list_length(&user_motd
->contents
) == 0)
327 sendto_one(source_p
, form_str(ERR_NOMOTD
), myname
, nick
);
331 sendto_one(source_p
, form_str(RPL_MOTDSTART
), myname
, nick
, me
.name
);
333 RB_DLINK_FOREACH(ptr
, user_motd
->contents
.head
)
336 sendto_one(source_p
, form_str(RPL_MOTD
), myname
, nick
, lineptr
->data
);
339 sendto_one(source_p
, form_str(RPL_ENDOFMOTD
), myname
, nick
);
343 cache_user_motd(void)
348 if(stat(ircd_paths
[IRCD_PATH_IRCD_MOTD
], &sb
) == 0)
350 local_tm
= localtime(&sb
.st_mtime
);
354 snprintf(user_motd_changed
, sizeof(user_motd_changed
),
356 local_tm
->tm_mday
, local_tm
->tm_mon
+ 1,
357 1900 + local_tm
->tm_year
, local_tm
->tm_hour
,
361 free_cachefile(user_motd
);
362 user_motd
= cache_file(ircd_paths
[IRCD_PATH_IRCD_MOTD
], "ircd.motd", 0);
368 * inputs - client to send motd to
369 * outputs - client is sent oper motd if exists
373 send_oper_motd(struct Client
*source_p
)
375 struct cacheline
*lineptr
;
378 if(oper_motd
== NULL
|| rb_dlink_list_length(&oper_motd
->contents
) == 0)
381 sendto_one(source_p
, form_str(RPL_OMOTDSTART
),
382 me
.name
, source_p
->name
);
384 RB_DLINK_FOREACH(ptr
, oper_motd
->contents
.head
)
387 sendto_one(source_p
, form_str(RPL_OMOTD
),
388 me
.name
, source_p
->name
, lineptr
->data
);
391 sendto_one(source_p
, form_str(RPL_ENDOFOMOTD
),
392 me
.name
, source_p
->name
);