3 * @author Mathew McBride
5 * This module implements an external pager hook for when notifcation
6 * of a new email is wanted.
7 * Based on bits of serv_funambol
8 * Contact: <matt@mcbridematt.dhs.org> / <matt@comalies>
19 #include <sys/types.h>
21 #if TIME_WITH_SYS_TIME
22 # include <sys/time.h>
26 # include <sys/time.h>
35 #include <sys/socket.h>
38 #include "citserver.h"
48 #include "internet_addressing.h"
50 #include "clientsocket.h"
51 #include "serv_pager.h"
53 #include "ctdl_module.h"
55 #define PAGER_CONFIG_MESSAGE "__ Push email settings __"
56 #define PAGER_CONFIG_TEXT "textmessage"
58 /*! \brief Create the notify message queue. We use the exact same room
59 * as the Funambol module.
61 * Run at server startup, creates FNBL_QUEUE_ROOM if it doesn't exist
62 * and sets as system room.
64 void create_pager_queue(void) {
65 struct ctdlroom qrbuf;
67 create_room(FNBL_QUEUE_ROOM, 3, "", 0, 1, 0, VIEW_MAILBOX);
70 * Make sure it's set to be a "system room" so it doesn't show up
71 * in the <K>nown rooms list for Aides.
73 if (lgetroom(&qrbuf, FNBL_QUEUE_ROOM) == 0) {
74 qrbuf.QRflags2 |= QR2_SYSTEM;
79 * \brief Run through the pager room queue
81 void do_pager_queue(void) {
82 static int doing_queue = 0;
85 * This is a simple concurrency check to make sure only one queue run
86 * is done at a time. We could do this with a mutex, but since we
87 * don't really require extremely fine granularity here, we'll do it
88 * with a static variable instead.
90 if (doing_queue) return;
94 * Go ahead and run the queue
96 lprintf(CTDL_DEBUG, "serv_pager: processing notify queue\n");
98 if (getroom(&CC->room, FNBL_QUEUE_ROOM) != 0) {
99 lprintf(CTDL_ERR, "Cannot find room <%s>\n", FNBL_QUEUE_ROOM);
102 CtdlForEachMessage(MSGS_ALL, 0L, NULL,
103 SPOOLMIME, NULL, notify_pager, NULL);
105 lprintf(CTDL_DEBUG, "serv_pager: queue run completed\n");
110 * \brief Call the external pager tool as set by the administrator
111 * @param msgnum The message number of the 'hint' message passed from do_pager_queue
112 * @param userdata userdata struct as passed by CtdlForEachMessage
115 void notify_pager(long msgnum, void *userdata) {
116 struct CtdlMessage *msg;
118 /* W means 'wireless', which contains the unix name */
119 msg = CtdlFetchMessage(msgnum, 1);
120 if ( msg->cm_fields['W'] == NULL) {
123 /* Are we allowed to push? */
124 if (IsEmptyStr(config.c_pager_program)) {
126 } else if (IsEmptyStr(config.c_pager_program) && IsEmptyStr(config.c_funambol_host)) {
129 lprintf(CTDL_INFO, "Pager alerter enabled\n");
132 /* Get the configuration. We might be allowed system wide but the user
133 may have configured otherwise */
134 long configMsgNum = pager_getConfigMessage(msg->cm_fields['W']);
135 int allowed = pager_isPagerAllowedByPrefs(configMsgNum);
136 if (allowed != 0 && pager_doesUserWant(configMsgNum) == 0) {
138 } else if (allowed != 0) {
141 char *num = pager_getUserPhoneNumber(configMsgNum);
143 snprintf(command, sizeof command, "%s %s -u %s", config.c_pager_program, num, msg->cm_fields['W']);
147 CtdlFreeMessage(msg);
149 todelete[0] = msgnum;
150 CtdlDeleteMessages(FNBL_QUEUE_ROOM, todelete, 1, "");
152 /*! \brief Get configuration message for pager/funambol system from the
153 * users "My Citadel Config" room
155 long pager_getConfigMessage(char *username) {
156 struct ctdlroom qrbuf; // scratch for room
157 struct ctdluser user; // ctdl user instance
158 char configRoomName[ROOMNAMELEN];
159 struct CtdlMessage *msg;
160 struct cdbdata *cdbfr;
161 long *msglist = NULL;
163 long confMsgNum = -1;
165 getuser(&user, username);
167 MailboxName(configRoomName, sizeof configRoomName, &user, USERCONFIGROOM);
169 getroom(&qrbuf, configRoomName);
170 /* Do something really, really stoopid here. Raid the room on ourselves,
171 loop through the messages manually and find it. I don't want
172 to use a CtdlForEachMessage callback here, as we would be
174 cdbfr = cdb_fetch(CDB_MSGLISTS, &qrbuf.QRnumber, sizeof(long));
176 msglist = (long *) cdbfr->ptr;
177 cdbfr->ptr = NULL; /* CtdlForEachMessage() now owns this memory */
178 num_msgs = cdbfr->len / sizeof(long);
181 lprintf(CTDL_DEBUG, "pager_getConfigMessage: No config messages found\n");
182 return -1; /* No messages at all? No further action. */
185 for (a = 0; a < num_msgs; ++a) {
186 msg = CtdlFetchMessage(msglist[a], 1);
188 if (msg->cm_fields['U'] != NULL && strncasecmp(msg->cm_fields['U'], PAGER_CONFIG_MESSAGE,
189 strlen(PAGER_CONFIG_MESSAGE)) == 0) {
190 confMsgNum = msglist[a];
192 CtdlFreeMessage(msg);
198 int pager_isPagerAllowedByPrefs(long configMsgNum) {
199 // Do a simple string search to see if 'textmessage' is selected as the
200 // type. This string would be at the very top of the message contents.
201 if (configMsgNum == -1) {
204 struct CtdlMessage *prefMsg;
205 prefMsg = CtdlFetchMessage(configMsgNum, 1);
206 char *msgContents = prefMsg->cm_fields['M'];
207 return strncasecmp(msgContents, PAGER_CONFIG_TEXT, strlen(PAGER_CONFIG_TEXT));
209 int pager_doesUserWant(long configMsgNum) {
210 if (configMsgNum == -1) {
213 struct CtdlMessage *prefMsg;
214 prefMsg = CtdlFetchMessage(configMsgNum, 1);
215 char *msgContents = prefMsg->cm_fields['M'];
216 return strncasecmp(msgContents, "none", 4);
218 /* warning: fetching twice gravely inefficient, will fix some time */
219 char *pager_getUserPhoneNumber(long configMsgNum) {
220 if (configMsgNum == -1) {
223 struct CtdlMessage *prefMsg;
224 prefMsg = CtdlFetchMessage(configMsgNum, 1);
225 char *msgContents = prefMsg->cm_fields['M'];
226 char *lines = strtok(msgContents, "textmessage\n");
229 CTDL_MODULE_INIT(pager)
231 create_pager_queue();
232 CtdlRegisterSessionHook(do_pager_queue, EVT_TIMER);
234 /* return our Subversion id for the Log */
235 return "$Id: serv_pager.c $";