1 #include <mysql/mysql.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <bglibs/str.h>
5 #include "qmail-autoresponder.h"
6 
7 const char usage_args[] = "USERNAME DOMAIN [TABLE_PREFIX]";
8 const char usage_post[] =
9 "  All the options except for -q, -D, and -N can be overridden\n"
10 "  in the autoresponder SQL table.\n";
11 
12 static long autoresponder;
13 static MYSQL mysql;
14 static str query;
15 static const char* prefix;
16 
str_cats_quoted(str * s,const char * p)17 static int str_cats_quoted(str* s, const char* p)
18 {
19   if (!str_catc(s, '\'')) return 0;
20   for (; *p != 0; ++p) {
21     switch (*p) {
22     case '\'':
23     case '\\':
24       if (!str_catc(s, '\\')) return 0;
25     default:
26       if (!str_catc(s, *p)) return 0;
27     }
28   }
29   return str_catc(s, '\'');
30 }
31 
do_select(const char * username,const char * domain)32 static MYSQL_RES* do_select(const char* username, const char* domain)
33 {
34   MYSQL_RES* result;
35   str_copy3s(&query,
36 	     "SELECT * "
37 	     "FROM ", prefix, "autoresponder "
38 	     "WHERE username");
39   if (username) {
40     str_catc(&query, '=');
41     str_cats_quoted(&query, username);
42   }
43   else
44     str_cats(&query, " IS NULL");
45   str_cats(&query, " AND domain=");
46   str_cats_quoted(&query, domain);
47   if (mysql_real_query(&mysql, query.s, query.len))
48     fail_temp("Could not select autoresponder.");
49   if ((result = mysql_store_result(&mysql)) == 0)
50     fail_temp("Error fetching result from database.");
51   return result;
52 }
53 
handle_field(const char * name,const char * value,unsigned int length)54 static void handle_field(const char* name,
55 			 const char* value,
56 			 unsigned int length)
57 {
58   if (strcmp(name, "id") == 0)
59     autoresponder = atol(value);
60   else if (strcmp(name, "response") == 0)
61     str_copyb(&response, value, length);
62   else if (memcmp(name, "opt_", 4) == 0)
63     handle_option(name + 4, value, length);
64 }
65 
init_autoresponder(int argc,char ** argv)66 void init_autoresponder(int argc, char** argv)
67 {
68   const char* username;
69   const char* domain;
70   MYSQL_RES* result;
71   MYSQL_ROW row;
72   unsigned long* lengths;
73   unsigned int num_fields;
74   unsigned int i;
75   MYSQL_FIELD* fields;
76 
77   if (argc < 2 || argc > 3)
78     usage("Incorrect number of command-line arguments.");
79   username = argv[0];
80   domain = argv[1];
81   prefix = (argc > 2) ? argv[2] : "";
82 
83   mysql_init(&mysql);
84   mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "qmail-autoresponder");
85   if (!mysql_real_connect(&mysql, getenv("MYSQL_HOST"),
86 			  getenv("MYSQL_USER"), getenv("MYSQL_PASS"),
87 			  getenv("MYSQL_DB"),
88 			  0, getenv("MYSQL_SOCKET"), 0))
89     fail_temp("Could not connect to MySQL");
90 
91   result = do_select(username, domain);
92   if (mysql_num_rows(result) == 0) {
93     mysql_free_result(result);
94     result = do_select(NULL, domain);
95     if (mysql_num_rows(result) == 0)
96       exit(0);
97   }
98 
99   if ((num_fields = mysql_num_fields(result)) == 0
100       || (fields = mysql_fetch_fields(result)) == 0
101       || (row = mysql_fetch_row(result)) == 0
102       || (lengths = mysql_fetch_lengths(result)) == 0)
103     fail_temp("Error fetching autoresponder from database.");
104   else {
105     for (i = 0; i < num_fields; ++i)
106       if (row[i])
107 	handle_field(fields[i].name, row[i], lengths[i]);
108     mysql_free_result(result);
109   }
110 }
111 
count_history(const char * sender)112 int count_history(const char* sender)
113 {
114   unsigned count = opt_msglimit;
115   int send_response;
116   MYSQL_RES* result;
117   MYSQL_ROW row;
118 
119   if (!opt_nodelete) {
120     str_copy3s(&query, "DELETE FROM ", prefix, "response "
121 	       "WHERE autoresponder=");
122     str_cati(&query, autoresponder);
123     str_cats(&query, " AND timestamp < (now() - INTERVAL ");
124     str_catu(&query, opt_timelimit);
125     str_cats(&query, " SECOND)");
126     if (mysql_real_query(&mysql, query.s, query.len))
127       fail_temp("Could not delete old records from database.");
128   }
129 
130   str_copy3s(&query, "SELECT count(*) "
131 	     "FROM ", prefix, "response "
132 	     "WHERE sent_response <> 0 "
133 	     "AND autoresponder=");
134   str_cati(&query, autoresponder);
135   str_cats(&query, " AND sender=");
136   str_cats_quoted(&query, sender);
137   str_cats(&query, " AND timestamp > (now() - INTERVAL ");
138   str_catu(&query, opt_timelimit);
139   str_cats(&query, " SECOND)");
140   if (mysql_real_query(&mysql, query.s, query.len))
141     fail_temp("Could not select count of records from database.");
142   if ((result = mysql_store_result(&mysql)) == 0 ||
143       (row = mysql_fetch_row(result)) == 0)
144     fail_temp("Error fetching count of records from database.");
145   else {
146     count = atol(row[0]);
147     mysql_free_result(result);
148   }
149 
150   send_response = count < opt_msglimit;
151 
152   return send_response;
153 }
154 
logit(const char * table,const char * sender,int responded)155 static int logit(const char* table, const char* sender, int responded)
156 {
157   str_copy4s(&query,
158 	     "INSERT INTO ", prefix, table, " "
159 	     "(autoresponder,timestamp,sent_response,sender) "
160 	     "VALUES (");
161   str_cati(&query, autoresponder);
162   str_cats(&query, ",now(),");
163   str_catu(&query, responded);
164   str_catc(&query, ',');
165   str_cats_quoted(&query, sender);
166   str_cats(&query, ")");
167   return mysql_real_query(&mysql, query.s, query.len);
168 }
169 
log_sender(const char * sender,int responded)170 void log_sender(const char* sender, int responded)
171 {
172   if (logit("response", sender, responded))
173     fail_temp("Could not insert response record into database.");
174   logit("log", sender, responded); /* Ignore errors for the log table */
175 }
176