ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/CreditCardReminder/CreditCardReminder.c
Revision: 744
Committed: 2006-04-08T00:22:17-07:00 (19 years, 2 months ago) by douglas
Content type: text/x-c
File size: 6799 byte(s)
Log Message:
Oops!

File Contents

# Content
1 // Credit Card Reminder
2 //
3 // Douglas Thrift
4 //
5 // $Id$
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <sys/types.h>
10 #include <regex.h>
11 #include <setjmp.h>
12 #include <stdio.h>
13 #include <sys/stat.h>
14 #include <time.h>
15
16 #include <c-client/c-client.h>
17
18 static jmp_buf environment;
19 static char *error = NULL;
20
21 static int check(int value, jmp_buf environment)
22 {
23 if (value == -1)
24 longjmp(environment, 1);
25
26 return value;
27 }
28
29 static char *fcheck(char *value, FILE *stream, jmp_buf environment)
30 {
31 if (!value)
32 {
33 if (ferror(stream))
34 longjmp(environment, 1);
35 else
36 {
37 clearerr(stdin);
38 printf("\n");
39
40 return "";
41 }
42 }
43
44 return value;
45 }
46
47 static void *mcheck(void *value, jmp_buf environment)
48 {
49 if (value == NIL)
50 longjmp(environment, 2);
51
52 return value;
53 }
54
55 static int regcheck(int value, const regex_t *regex, jmp_buf environment)
56 {
57 if (value && value != REG_NOMATCH)
58 {
59 char exception[regerror(value, regex, NULL, 0)];
60
61 regerror(value, regex, exception, sizeof (exception));
62 longjmp(environment, (int)exception);
63 }
64
65 return value;
66 }
67
68 inline static unsigned short mdate(const struct tm *date)
69 {
70 return ((date->tm_year + 1900 - BASEYEAR) << 9) + ((date->tm_mon + 1) << 5) + date->tm_mday;
71 }
72
73 static void getnext(const struct tm *today, jmp_buf environment)
74 {
75 struct tm date = *today;
76
77 --date.tm_mon;
78
79 timegm(&date);
80
81 # include <c-client/linkage.c>
82
83 MAILSTREAM *stream = mcheck(mail_open(NIL, "{reptile.douglasthrift.net/novalidate-cert/tls}", OP_READONLY | OP_DEBUG), environment);
84 STRINGLIST from = { .text = { .data = (unsigned char *)"wellsfargo.com", .size = 14 } }, body = { .text = { .data = (unsigned char *)" is due on ", .size = 11 } };
85 SEARCHPGM search = { .from = &from, .body = &body, .since = mdate(&date) };
86 SORTPGM sort = { .reverse = 1, .function = SORTARRIVAL };
87 unsigned long *messages = mcheck(mail_sort(stream, "ISO-8859-1", &search, &sort, SE_UID), environment);
88 regex_t due;
89
90 regcheck(regcomp(&due, "^.* is due on ([01][0-9]/[0-3][0-9]/[0-9]{4}).*$", REG_EXTENDED), &due, environment);
91
92 for (unsigned long *message = messages; *message != 0; ++message)
93 {
94 unsigned long size;
95 char *body = mcheck(mail_fetchbody_full(stream, *message, "1", &size, FT_UID | FT_PEEK), environment);
96 regmatch_t match[2] = { { .rm_eo = size } };
97
98 if (!regcheck(regexec(&due, body, 2, match, REG_STARTEND), &due, environment))
99 {
100 char date[match[1].rm_eo - match[1].rm_so + 1];
101
102 strlcpy(date, body + match[1].rm_so, sizeof (date));
103 assert(sizeof (date) == 11);
104
105 struct tm due;
106
107 strptime(date, "%m/%d/%Y", &due);
108 strftime(date, sizeof (date), "%F", &due);
109
110 char *path;
111
112 check(asprintf(&path, "%s/.CreditCardReminder.data", getenv("HOME")), environment);
113
114 FILE *file = fopen(path, "w");
115
116 if (!file)
117 longjmp(environment, 1);
118
119 free(path);
120 check(fprintf(file, "%s\n", date), environment);
121 check(fclose(file), environment);
122
123 break;
124 }
125 }
126
127 fs_give((void *)&messages);
128 mail_close(stream);
129 }
130
131 int main(int argc, char *argv[])
132 {
133 int exception;
134
135 switch (exception = setjmp(environment))
136 {
137 case 0:
138 break;
139 case 1:
140 perror(argv[0]);
141
142 return 1;
143 case 2:
144 fprintf(stderr, "%s: %s\n", argv[0], error);
145 free(error);
146
147 return 1;
148 default:
149 fprintf(stderr, "%s: %s\n", argv[0], (char *)exception);
150
151 return 1;
152 }
153
154 umask(0077);
155
156 struct tm today, next = { .tm_mday = 1, .tm_year = 70 };
157
158 {
159 time_t now = time(NULL);
160
161 gmtime_r(&now, &today);
162
163 today.tm_sec = 0;
164 today.tm_min = 0;
165 today.tm_hour = 0;
166 }
167
168 {
169 jmp_buf environment_;
170
171 switch (exception = setjmp(environment_))
172 {
173 case 0:
174 break;
175 case 1:
176 if (errno == ENOENT)
177 {
178 getnext(&today, environment);
179
180 break;
181 }
182 default:
183 longjmp(environment, exception);
184 }
185
186 char *path;
187
188 check(asprintf(&path, "%s/.CreditCardReminder.data", getenv("HOME")), environment);
189
190 FILE *file = fopen(path, "r");
191
192 if (!file)
193 longjmp(environment_, 1);
194
195 free(path);
196
197 size_t size;
198 char *line = fcheck(fgetln(file, &size), file, environment);
199
200 line[--size] = '\0';
201
202 if (!strptime(line, "%F", &next))
203 longjmp(environment, 1);
204
205 check(fclose(file), environment);
206 }
207
208 char date[11];
209
210 strftime(date, sizeof (date), "%F", &next);
211 fprintf(stderr, "%s\n", date);
212
213 return 0;
214 }
215
216 void mm_flags(MAILSTREAM *stream, unsigned long number)
217 {
218 printf("flags:\n number = %lu\n", number);
219 }
220
221 void mm_status(MAILSTREAM *stream, char *mailbox, MAILSTATUS *status)
222 {
223 printf("mailbox %s:\n", mailbox);
224
225 if (status->flags & SA_MESSAGES)
226 printf(" messages = %lu\n", status->messages);
227
228 if (status->flags & SA_RECENT)
229 printf(" recent = %lu\n", status->recent);
230
231 if (status->flags & SA_UNSEEN)
232 printf(" unseen = %lu\n", status->unseen);
233
234 if (status->flags & SA_UIDNEXT)
235 printf(" uidnext = %lu\n", status->uidnext);
236
237 if (status->flags & SA_UIDVALIDITY)
238 printf(" uidvalidity = %lu\n", status->uidvalidity);
239 }
240
241 void mm_searched(MAILSTREAM *stream, unsigned long number)
242 {
243 printf("searched:\n number = %lu\n", number);
244 }
245
246 void mm_exists(MAILSTREAM *stream, unsigned long number)
247 {
248 printf("exists:\n number = %lu\n", number);
249 }
250
251 void mm_expunged(MAILSTREAM *stream, unsigned long number)
252 {
253 printf("expunged:\n number = %lu\n", number);
254 }
255
256 void mm_list(MAILSTREAM *stream, int delim, char *name, long attrib)
257 {
258 printf("list");
259 }
260
261 void mm_lsub(MAILSTREAM *stream, int delim, char *name, long attrib)
262 {
263 printf("lsub");
264 }
265
266 void mm_notify(MAILSTREAM *stream, char *string, long errflg)
267 {
268 char *flag;
269
270 asprintf(&flag, "%li", errflg);
271 printf("notify %s:\n string = %s\n", errflg == NIL ? "NIL" : errflg == WARN ? "WARN" : errflg == ERROR ? "ERROR" : flag, string);
272 free(flag);
273 }
274
275 void mm_log(char *string, long errflg)
276 {
277 /* char *flag;
278
279 asprintf(&flag, "%li", errflg);
280 printf("log %s:\n string = %s\n", errflg == NIL ? "NIL" : errflg == PARSE ? "PARSE" : errflg == WARN ? "WARN" : errflg == ERROR ? "ERROR" : flag, string);
281 free(flag);*/
282
283 if (errflg == ERROR)
284 asprintf(&error, "%s", string);
285 }
286
287 void mm_dlog(char *string)
288 {
289 printf("%s\n", string);
290 }
291
292 void mm_login(NETMBX *mb, char *user, char *pwd, long trial)
293 {
294 strcpy(user, "douglas");
295
296 char *path;
297
298 check(asprintf(&path, "%s/.CreditCardReminder.pass", getenv("HOME")), environment);
299
300 FILE *file = fopen(path, "r");
301
302 if (!file)
303 longjmp(environment, 1);
304
305 free(path);
306
307 size_t size;
308 char *line = fcheck(fgetln(file, &size), file, environment);
309
310 strlcpy(pwd, line, size);
311 }
312
313 void mm_critical(MAILSTREAM *stream)
314 {
315 printf("critical\n");
316 }
317
318 void mm_nocritical(MAILSTREAM *stream)
319 {
320 printf("nocritical\n");
321 }
322
323 long mm_diskerror(MAILSTREAM *stream, long errcode, long serious)
324 {
325 printf("diskerror:\n errcode = %li\n serious = %li\n", errcode, serious);
326
327 return 1;
328 }
329
330 void mm_fatal(char *string)
331 {
332 printf("fatal:\n string = %s\n", string);
333 }

Properties

Name Value
svn:eol-style native
svn:keywords Id