]> code.citadel.org Git - citadel.git/blob - citadel/serv_expire.c
* serv_expire.c: purge ops are now a command instead of a cleanup
[citadel.git] / citadel / serv_expire.c
1 /*
2  * serv_expire.c
3  *
4  * This module handles the expiry of old messages and the purging of old users.
5  *
6  */
7 /* $Id$ */
8
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <signal.h>
14 #include <pwd.h>
15 #include <errno.h>
16 #include <sys/types.h>
17 #include <sys/time.h>
18 #include <sys/wait.h>
19 #include <string.h>
20 #include <limits.h>
21 #include <pthread.h>
22 #include "citadel.h"
23 #include "server.h"
24 #include <syslog.h>
25 #include <time.h>
26 #include "sysdep_decls.h"
27 #include "citserver.h"
28 #include "support.h"
29 #include "config.h"
30 #include "dynloader.h"
31 #include "room_ops.h"
32 #include "policy.h"
33 #include "database.h"
34 #include "msgbase.h"
35 #include "user_ops.h"
36
37 struct PurgedUser {
38         struct PurgedUser *next;
39         char name[26];
40         };
41
42 struct PurgedUser *plist = NULL;
43
44 extern struct CitContext *ContextList;
45
46 #define MODULE_NAME     "Expire old messages, users, rooms"
47 #define MODULE_AUTHOR   "Art Cancro"
48 #define MODULE_EMAIL    "ajc@uncnsrd.mt-kisco.ny.us"
49 #define MAJOR_VERSION   0
50 #define MINOR_VERSION   1
51
52 static struct DLModule_Info info = {
53         MODULE_NAME,
54         MODULE_AUTHOR,
55         MODULE_EMAIL,
56         MAJOR_VERSION,
57         MINOR_VERSION
58         };
59
60 void DoPurgeMessages(struct quickroom *qrbuf) {
61         struct ExpirePolicy epbuf;
62         long delnum;
63         time_t xtime, now;
64         char msgid[64];
65         int a;
66
67         time(&now);
68         GetExpirePolicy(&epbuf, qrbuf);
69         
70         /*
71         lprintf(9, "ExpirePolicy for <%s> is <%d> <%d>\n",
72                 qrbuf->QRname, epbuf.expire_mode, epbuf.expire_value);
73         */
74
75         /* If the room is set to never expire messages ... do nothing */
76         if (epbuf.expire_mode == EXPIRE_NEXTLEVEL) return;
77         if (epbuf.expire_mode == EXPIRE_MANUAL) return;
78
79         begin_critical_section(S_QUICKROOM);
80         get_msglist(qrbuf);
81         
82         /* Nothing to do if there aren't any messages */
83         if (CC->num_msgs == 0) {
84                 end_critical_section(S_QUICKROOM);
85                 return;
86                 }
87
88         /* If the room is set to expire by count, do that */
89         if (epbuf.expire_mode == EXPIRE_NUMMSGS) {
90                 while (CC->num_msgs > epbuf.expire_value) {
91                         delnum = MessageFromList(0);
92                         lprintf(5, "Expiring message %ld\n", delnum);
93                         cdb_delete(CDB_MSGMAIN, &delnum, sizeof(long));
94                         memcpy(&CC->msglist[0], &CC->msglist[1],
95                                 (sizeof(long)*(CC->num_msgs - 1)));
96                         CC->num_msgs = CC->num_msgs - 1;
97                         }
98                 }
99
100         /* If the room is set to expire by age... */
101         if (epbuf.expire_mode == EXPIRE_AGE) {
102                 for (a=0; a<(CC->num_msgs); ++a) {
103                         delnum = MessageFromList(a);
104                         sprintf(msgid, "%ld", delnum);
105                         xtime = output_message(msgid, MT_DATE, 0, 0);
106
107                         if ((xtime > 0L)
108                            && (now - xtime > (time_t)(epbuf.expire_value * 86400L))) {
109                                 cdb_delete(CDB_MSGMAIN, &delnum, sizeof(long));
110                                 SetMessageInList(a, 0L);
111                                 lprintf(5, "Expiring message %ld\n", delnum);
112                                 }
113                         }
114                 }
115         CC->num_msgs = sort_msglist(CC->msglist, CC->num_msgs);
116         put_msglist(qrbuf);
117         end_critical_section(S_QUICKROOM);
118         }
119
120 void PurgeMessages(void) {
121         lprintf(5, "PurgeMessages() called\n");
122         ForEachRoom(DoPurgeMessages);
123         }
124
125
126 void do_user_purge(struct usersupp *us) {
127         int purge;
128         time_t now;
129         time_t purge_time;
130         struct PurgedUser *pptr;
131
132         /* Set purge time; if the user overrides the system default, use it */
133         if (us->USuserpurge > 0) {
134                 purge_time = ((time_t)us->USuserpurge) * 86400L;
135                 }
136         else {
137                 purge_time = ((time_t)config.c_userpurge) * 86400L;
138                 }
139
140         /* The default rule is to not purge. */
141         purge = 0;
142
143         /* If the user hasn't called in two months, his/her account
144          * has expired, so purge the record.
145          */
146         now = time(NULL);
147         if ((now - us->lastcall) > purge_time) purge = 1;
148
149         /* If the user set his/her password to 'deleteme', he/she
150          * wishes to be deleted, so purge the record.
151          */
152         if (!strcasecmp(us->password, "deleteme")) purge = 1;
153
154         /* If the record is marked as permanent, don't purge it.
155          */
156         if (us->flags & US_PERM) purge = 0;
157
158         /* If the access level is 0, the record should already have been
159          * deleted, but maybe the user was logged in at the time or something.
160          * Delete the record now.
161          */
162         if (us->axlevel == 0) purge = 1;
163
164         /* 0 calls is impossible.  If there are 0 calls, it must
165          * be a corrupted record, so purge it.
166          */
167         if (us->timescalled == 0) purge = 1;
168
169         if (purge == 1) {
170                 pptr = (struct PurgedUser *) malloc(sizeof(struct PurgedUser));
171                 pptr->next = plist;
172                 strcpy(pptr->name, us->fullname);
173                 plist = pptr;
174                 }
175
176         }
177
178
179
180 int PurgeUsers(void) {
181         struct PurgedUser *pptr;
182         int num_users_purged = 0;
183
184         lprintf(5, "PurgeUsers() called\n");
185         if (config.c_userpurge > 0) {
186                 ForEachUser(do_user_purge);
187                 }
188
189         while (plist != NULL) {
190                 purge_user(plist->name);
191                 pptr = plist->next;
192                 free(plist);
193                 plist = pptr;
194                 ++num_users_purged;
195                 }
196
197         lprintf(5, "Purged %d users.\n", num_users_purged);
198         return(num_users_purged);
199         }
200
201
202 void cmd_expi(char *argbuf) {
203         char cmd[256];
204         int retval;
205
206
207         if ((!(CC->logged_in))&&(!(CC->internal_pgm))) {
208                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
209                 return;
210                 }
211
212         if ((!is_room_aide()) && (!(CC->internal_pgm)) ) {
213                 cprintf("%d Higher access required.\n",
214                         ERROR+HIGHER_ACCESS_REQUIRED);
215                 return;
216                 }
217
218         extract(cmd, argbuf, 0);
219         if (!strcasecmp(cmd, "users")) {
220                 retval = PurgeUsers();
221                 cprintf("%d Purged %d users.\n", OK, retval);
222                 return;
223                 }
224         else if (!strcasecmp(cmd, "messages")) {
225                 PurgeMessages();
226                 cprintf("%d Finished purging messages.\n", OK);
227                 return;
228                 }
229         else {
230                 cprintf("%d Invalid command.\n", ERROR+ILLEGAL_VALUE);
231                 return;
232                 }
233         }
234
235
236 struct DLModule_Info *Dynamic_Module_Init(void)
237 {
238    CtdlRegisterProtoHook(cmd_expi, "EXPI", "Expire old system objects");
239    return &info;
240 }