Big change to the ldap code to break its dependancy on serv_vcard.c and
[citadel.git] / citadel / modules / pager / serv_pager.c
1 /*
2  * This module implements an external pager hook for when notifcation
3  * of a new email is wanted.
4  * Based on bits of serv_funambol
5  */
6
7 #include "sysdep.h"
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <fcntl.h>
12 #include <signal.h>
13 #include <pwd.h>
14 #include <errno.h>
15 #include <sys/types.h>
16
17 #if TIME_WITH_SYS_TIME
18 # include <sys/time.h>
19 # include <time.h>
20 #else
21 # if HAVE_SYS_TIME_H
22 #  include <sys/time.h>
23 # else
24 #  include <time.h>
25 # endif
26 #endif
27
28 #include <sys/wait.h>
29 #include <string.h>
30 #include <limits.h>
31 #include <sys/socket.h>
32 #include "citadel.h"
33 #include "server.h"
34 #include "citserver.h"
35 #include "support.h"
36 #include "config.h"
37 #include "control.h"
38 #include "room_ops.h"
39 #include "user_ops.h"
40 #include "policy.h"
41 #include "database.h"
42 #include "msgbase.h"
43 #include "tools.h"
44 #include "internet_addressing.h"
45 #include "domain.h"
46 #include "clientsocket.h"
47 #include "serv_pager.h"
48
49 #include "ctdl_module.h"
50
51 #define PAGER_CONFIG_MESSAGE "__ Push email settings __"
52 #define PAGER_CONFIG_TEXT  "textmessage"
53
54 /*
55  * Create the notify message queue. We use the exact same room 
56  */
57 void create_pager_queue(void) {
58         struct ctdlroom qrbuf;
59
60         create_room(FNBL_QUEUE_ROOM, 3, "", 0, 1, 0, VIEW_MAILBOX);
61
62         /*
63          * Make sure it's set to be a "system room" so it doesn't show up
64          * in the <K>nown rooms list for Aides.
65          */
66         if (lgetroom(&qrbuf, FNBL_QUEUE_ROOM) == 0) {
67                 qrbuf.QRflags2 |= QR2_SYSTEM;
68                 lputroom(&qrbuf);
69         }
70 }
71 void do_pager_queue(void) {
72         static int doing_queue = 0;
73
74         /*
75          * This is a simple concurrency check to make sure only one queue run
76          * is done at a time.  We could do this with a mutex, but since we
77          * don't really require extremely fine granularity here, we'll do it
78          * with a static variable instead.
79          */
80         if (doing_queue) return;
81         doing_queue = 1;
82
83         /* 
84          * Go ahead and run the queue
85          */
86         lprintf(CTDL_DEBUG, "serv_pager: processing notify queue\n");
87
88         if (getroom(&CC->room, FNBL_QUEUE_ROOM) != 0) {
89                 lprintf(CTDL_ERR, "Cannot find room <%s>\n", FNBL_QUEUE_ROOM);
90                 return;
91         }
92         CtdlForEachMessage(MSGS_ALL, 0L, NULL,
93                 SPOOLMIME, NULL, notify_pager, NULL);
94
95         lprintf(CTDL_DEBUG, "serv_pager: queue run completed\n");
96         doing_queue = 0;
97 }
98
99 /*
100  * Call the external tool
101  */
102 void notify_pager(long msgnum, void *userdata) {
103         struct CtdlMessage *msg;
104         struct ctdlroom qrbuf;
105         
106         /* W means 'wireless', which contains the unix name */
107         msg = CtdlFetchMessage(msgnum, 1);
108         if ( msg->cm_fields['W'] == NULL) {
109                 goto nuke;
110         }
111         /* Are we allowed to push? */
112         if (IsEmptyStr(config.c_pager_program)) {
113                 return;
114         } else if (IsEmptyStr(config.c_pager_program) && IsEmptyStr(config.c_funambol_host)) {
115                 goto nuke;
116         } else {
117                 lprintf(CTDL_INFO, "Pager alerter enabled\n");  
118         }
119
120         /* Get the configuration. We might be allowed system wide but the user
121                 may have configured otherwise */
122         long configMsgNum = pager_getConfigMessage(msg->cm_fields['W']);
123         int allowed = pager_isPagerAllowedByPrefs(configMsgNum);
124         if (allowed != 0 && pager_doesUserWant(configMsgNum) == 0) {
125                 goto nuke;
126         } else if (allowed != 0) {
127                 return;
128         }
129         char *num = pager_getUserPhoneNumber(configMsgNum);
130         char command[SIZ];
131         snprintf(command, sizeof command, "%s %s -u %s", config.c_pager_program, num, &msg->cm_fields['W']);
132         system(command);
133         
134         nuke:
135         CtdlFreeMessage(msg);
136         long todelete[1];
137         todelete[0] = msgnum;
138         CtdlDeleteMessages(FNBL_QUEUE_ROOM, todelete, 1, "");
139 }
140
141 long pager_getConfigMessage(char *username) {
142         struct ctdlroom qrbuf; // scratch for room
143         struct ctdluser user; // ctdl user instance
144         char configRoomName[ROOMNAMELEN];
145         struct CtdlMessage *template;
146         struct CtdlMessage *msg;
147         struct cdbdata *cdbfr;
148         long *msglist = NULL;
149         int num_msgs = 0;
150         long confMsgNum = -1;
151         // Get the user
152         getuser(&user, username);
153         
154         MailboxName(configRoomName, sizeof configRoomName, &user, USERCONFIGROOM);
155         int prefroom = getroom(&qrbuf, configRoomName);
156         
157         /* Do something really, really stoopid here. Raid the room on ourselves,
158                 loop through the messages manually and find it. I don't want 
159                 to use a CtdlForEachMessage callback here, as we would be 
160                 already in one */
161         cdbfr = cdb_fetch(CDB_MSGLISTS, &qrbuf.QRnumber, sizeof(long));
162         if (cdbfr != NULL) {
163                 msglist = (long *) cdbfr->ptr;
164                 cdbfr->ptr = NULL;      /* CtdlForEachMessage() now owns this memory */
165                 num_msgs = cdbfr->len / sizeof(long);
166                 cdb_free(cdbfr);
167         } else {
168                 return -1;      /* No messages at all?  No further action. */
169         }
170         int a;
171         for (a = 0; a < num_msgs; ++a) {
172                                 msg = CtdlFetchMessage(msglist[a], 1);
173                                 if (msg != NULL) {
174                                         if (msg->cm_fields['U'] != NULL && strncasecmp(msg->cm_fields['U'], PAGER_CONFIG_MESSAGE, 
175                                                 strlen(PAGER_CONFIG_MESSAGE)) == 0) {
176                                                 confMsgNum = msglist[a];
177                                         }
178                                         CtdlFreeMessage(msg);
179                                 }
180         }
181         return confMsgNum;
182
183 }
184 int pager_isPagerAllowedByPrefs(long configMsgNum) {
185         // Do a simple string search to see if 'textmessage' is selected as the 
186         // type. This string would be at the very top of the message contents.
187         if (configMsgNum == -1) {
188                 return -1;
189         }
190         struct CtdlMessage *prefMsg;
191         prefMsg = CtdlFetchMessage(configMsgNum, 1);
192         char *msgContents = prefMsg->cm_fields['M'];
193         return strncasecmp(msgContents, PAGER_CONFIG_TEXT, strlen(PAGER_CONFIG_TEXT));
194 }
195 int pager_doesUserWant(long configMsgNum) {
196         if (configMsgNum == -1) {
197                 return -1;
198         }
199         struct CtdlMessage *prefMsg;
200         prefMsg = CtdlFetchMessage(configMsgNum, 1);
201         char *msgContents = prefMsg->cm_fields['M'];
202         return strncasecmp(msgContents, "none", 4);
203 }
204         /* warning: fetching twice gravely inefficient, will fix some time */
205 char *pager_getUserPhoneNumber(long configMsgNum) {
206         if (configMsgNum == -1) {
207                 return;
208         }
209         struct CtdlMessage *prefMsg;
210         prefMsg = CtdlFetchMessage(configMsgNum, 1);
211         char *msgContents = prefMsg->cm_fields['M'];
212         char *lines = strtok(msgContents, "textmessage\n");
213         return lines;
214 }
215 CTDL_MODULE_INIT(pager)
216 {
217         create_pager_queue();
218         CtdlRegisterSessionHook(do_pager_queue, EVT_TIMER);
219
220         /* return our Subversion id for the Log */
221         return "$Id: serv_pager.c $";
222 }