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