src/account.[ch]
[claws.git] / src / quote_fmt_parse.y
1 %{
2
3 #include "defs.h"
4
5 #include <glib.h>
6 #include <ctype.h>
7
8 #include "procmsg.h"
9 #include "procmime.h"
10 #include "utils.h"
11 #include "intl.h"
12 #include "procheader.h"
13
14 #include "quote_fmt.h"
15 #include "quote_fmt_lex.h"
16
17 /* decl */
18 /*
19 flex quote_fmt.l
20 bison -p quote_fmt quote_fmt.y
21 */
22
23 int yylex(void);
24
25 static MsgInfo *msginfo = NULL;
26 static gboolean *visible = NULL;
27 static gint maxsize = 0;
28 static gint stacksize = 0;
29
30 static gchar *buffer = NULL;
31 static gint bufmax = 0;
32 static gint bufsize = 0;
33 static const gchar *quote_str = NULL;
34 static const gchar *body = NULL;
35 static gint error = 0;
36
37 static void add_visibility(gboolean val)
38 {
39         stacksize++;
40         if (maxsize < stacksize) {
41                 maxsize += 128;
42                 visible = g_realloc(visible, maxsize * sizeof(gboolean));
43                 if (visible == NULL)
44                         maxsize = 0;
45         }
46
47         visible[stacksize - 1] = val;
48 }
49
50 static void remove_visibility(void)
51 {
52         stacksize--;
53 }
54
55 static void add_buffer(const gchar *s)
56 {
57         gint len;
58
59         len = strlen(s);
60         if (bufsize + len + 1 > bufmax) {
61                 if (bufmax == 0)
62                         bufmax = 128;
63                 while (bufsize + len + 1 > bufmax)
64                         bufmax *= 2;
65                 buffer = g_realloc(buffer, bufmax);
66         }
67         strcpy(buffer + bufsize, s);
68         bufsize += len;
69 }
70
71 static void flush_buffer(void)
72 {
73         if (buffer != NULL)
74                 *buffer = '\0';
75         bufsize = 0;
76 }
77
78 gchar *quote_fmt_get_buffer(void)
79 {
80         if (error != 0)
81                 return NULL;
82         else
83                 return buffer;
84 }
85
86 #define INSERT(buf) \
87         if (stacksize != 0 && visible[stacksize - 1]) \
88                 add_buffer(buf)
89
90 #define INSERT_CHARACTER(chr) \
91         if (stacksize != 0 && visible[stacksize - 1]) { \
92                 gchar tmp[2]; \
93                 tmp[0] = (chr); \
94                 tmp[1] = '\0'; \
95                 add_buffer(tmp); \
96         }
97
98 void quote_fmt_init(MsgInfo *info, const gchar *my_quote_str,
99                     const gchar *my_body)
100 {
101         quote_str = my_quote_str;
102         body = my_body;
103         msginfo = info;
104         stacksize = 0;
105         add_visibility(TRUE);
106         if (buffer != NULL)
107                 *buffer = 0;
108         bufsize = 0;
109         error = 0;
110 }
111
112 void quote_fmterror(char *str)
113 {
114         g_warning(_("Error: %s\n"), str);
115         error = 1;
116 }
117
118 int quote_fmtwrap(void)
119 {
120         return 1;
121 }
122
123 static int isseparator(char ch)
124 {
125         return isspace(ch) || ch == '.' || ch == '-';
126 }
127 %}
128
129 %union {
130         char chr;
131         char str[256];
132 }
133
134 %token SHOW_NEWSGROUPS
135 %token SHOW_DATE SHOW_FROM SHOW_FULLNAME SHOW_FIRST_NAME SHOW_LAST_NAME
136 %token SHOW_SENDER_INITIAL SHOW_SUBJECT SHOW_TO SHOW_MESSAGEID
137 %token SHOW_PERCENT SHOW_CC SHOW_REFERENCES SHOW_MESSAGE
138 %token SHOW_QUOTED_MESSAGE SHOW_BACKSLASH SHOW_TAB
139 %token SHOW_QUOTED_MESSAGE_NO_SIGNATURE SHOW_MESSAGE_NO_SIGNATURE
140 %token SHOW_EOL SHOW_QUESTION_MARK SHOW_PIPE SHOW_OPARENT SHOW_CPARENT
141 %token QUERY_DATE QUERY_FROM
142 %token QUERY_FULLNAME QUERY_SUBJECT QUERY_TO QUERY_NEWSGROUPS
143 %token QUERY_MESSAGEID QUERY_CC QUERY_REFERENCES
144 %token INSERT_FILE INSERT_PROGRAMOUTPUT
145 %token OPARENT CPARENT
146 %token CHARACTER
147 %token SHOW_DATE_EXPR
148
149 %start quote_fmt
150
151 %token <chr> CHARACTER
152 %type <chr> character
153 %type <str> string
154
155 %%
156
157 quote_fmt:
158         character_or_special_or_insert_or_query_list;
159
160 character_or_special_or_insert_or_query_list:
161         character_or_special_or_insert_or_query character_or_special_or_insert_or_query_list
162         | character_or_special_or_insert_or_query ;
163
164 character_or_special_or_insert_or_query:
165         special
166         | character
167         {
168                 INSERT_CHARACTER($1);
169         }
170         | query ;
171         | insert ;
172
173 character:
174         CHARACTER
175         ;
176
177 string:
178         CHARACTER
179         {
180                 $$[0] = $1;
181                 $$[1] = '\0';
182         }
183         | string CHARACTER
184         {
185                 strcpy($$, $1);
186                 $$[strlen($$) + 1] = '\0';
187                 $$[strlen($$)] = $2;
188         };
189
190 special:
191         SHOW_NEWSGROUPS
192         {
193                 if (msginfo->newsgroups)
194                         INSERT(msginfo->newsgroups);
195         }
196         | SHOW_DATE_EXPR OPARENT string CPARENT
197         {
198                 /* 
199                  * ALF - GNU C's strftime() has a nice format specifier 
200                  * for time zone offset (%z). Non-standard however, so 
201                  * emulate it.
202                  */
203                 if (msginfo->date) {
204                         char  result[100];
205                         char *rptr;
206                         char  zone[6];
207                         struct tm lt;
208                         const char *fptr;
209                         const char *zptr;
210
211 #define RLEFT (sizeof result) - (rptr - result) 
212 #define STR_SIZE(x) (sizeof (x) - 1)
213
214                         zone[0] = 0;
215
216                         if (procheader_date_parse_to_tm(msginfo->date, &lt, zone)) {
217                                 /*
218                                  * break up format string in tiny bits delimited by valid %z's and 
219                                  * feed it to strftime(). don't forget that '%%z' mean literal '%z'.
220                                  */
221                                 for (rptr = result, fptr = $3; fptr && *fptr && rptr < &result[sizeof result - 1];) {
222                                         int         perc;
223                                         const char *p;
224                                         char       *tmp;
225                                         
226                                         if (NULL != (zptr = strstr(fptr, "%z"))) {
227                                                 /*
228                                                  * count nr. of prepended percent chars
229                                                  */
230                                                 for (perc = 0, p = zptr; p && p >= $3 && *p == '%'; p--, perc++)
231                                                         ;
232                                                 /*
233                                                  * feed to strftime()
234                                                  */
235                                                 tmp = g_strndup(fptr, zptr - fptr + (perc % 2 ? 0 : STR_SIZE("%z")));
236                                                 if (tmp) {
237                                                         rptr += strftime(rptr, RLEFT, tmp, &lt);
238                                                         g_free(tmp);
239                                                 }
240                                                 /*
241                                                  * append time zone offset
242                                                  */
243                                                 if (zone[0] && perc % 2) 
244                                                         rptr += g_snprintf(rptr, RLEFT, "%s", zone);
245                                                 fptr = zptr + STR_SIZE("%z");
246                                         } else {
247                                                 rptr += strftime(rptr, RLEFT, fptr, &lt);
248                                                 fptr  = NULL;
249                                         }
250                                 }
251                                 
252                                 INSERT(result);
253                         }
254 #undef STR_SIZE                 
255 #undef RLEFT                    
256                 }
257         }
258         | SHOW_DATE
259         {
260                 if (msginfo->date)
261                         INSERT(msginfo->date);
262         }
263         | SHOW_FROM
264         {
265                 if (msginfo->from)
266                         INSERT(msginfo->from);
267         }
268         | SHOW_FULLNAME
269         {
270                 if (msginfo->fromname)
271                         INSERT(msginfo->fromname);
272         }
273         | SHOW_FIRST_NAME
274         {
275                 if (msginfo->fromname) {
276                         gchar *p;
277                         gchar *str;
278
279                         str = alloca(strlen(msginfo->fromname) + 1);
280                         if (str != NULL) {
281                                 strcpy(str, msginfo->fromname);
282                                 p = str;
283                                 while (*p && !isspace(*p)) p++;
284                                 *p = '\0';
285                                 INSERT(str);
286                         }
287                 }
288         }
289         | SHOW_LAST_NAME
290         {
291                 /* This probably won't work together very well with Middle
292                  names and the like - thth */
293                 if (msginfo->fromname) {
294                         gchar *p;
295                         gchar *str;
296
297                         str = alloca(strlen(msginfo->fromname) + 1);
298                         if (str != NULL) {
299                                 strcpy(str, msginfo->fromname);
300                                 p = str;
301                                 while (*p && !isspace(*p)) p++;
302                                 if (*p) {
303                                     /* We found a space. Get first none-space char and
304                                      insert rest of string from there. */
305                                     while (*p && isspace(*p)) p++;
306                                     if (*p) {
307                                         INSERT(p);
308                                     } else {
309                                         /* If there is no none-space char, just insert
310                                          whole fromname. */
311                                         INSERT(str);
312                                     }
313                                 } else {
314                                     /* If there is no space, just insert whole fromname. */
315                                     INSERT(str);
316                                 }
317                         }
318                 }
319         }
320         | SHOW_SENDER_INITIAL
321         {
322 #define MAX_SENDER_INITIAL 20
323                 if (msginfo->fromname) {
324                         gchar tmp[MAX_SENDER_INITIAL];
325                         gchar *p;
326                         gchar *cur;
327                         gint len = 0;
328
329                         p = msginfo->fromname;
330                         cur = tmp;
331                         while (*p) {
332                                 if (*p && isalnum(*p)) {
333                                         *cur = toupper(*p);
334                                                 cur++;
335                                         len++;
336                                         if (len >= MAX_SENDER_INITIAL - 1)
337                                                 break;
338                                 } else
339                                         break;
340                                 while (*p && !isseparator(*p)) p++;
341                                 while (*p && isseparator(*p)) p++;
342                         }
343                         *cur = '\0';
344                         INSERT(tmp);
345                 }
346         }
347         | SHOW_SUBJECT
348         {
349                 if (msginfo->subject)
350                         INSERT(msginfo->subject);
351         }
352         | SHOW_TO
353         {
354                 if (msginfo->to)
355                         INSERT(msginfo->to);
356         }
357         | SHOW_MESSAGEID
358         {
359                 if (msginfo->msgid)
360                         INSERT(msginfo->msgid);
361         }
362         | SHOW_PERCENT
363         {
364                 INSERT("%");
365         }
366         | SHOW_CC
367         {
368                 if (msginfo->cc)
369                         INSERT(msginfo->cc);
370         }
371         | SHOW_REFERENCES
372         {
373                 /* if (msginfo->references)
374                         INSERT(msginfo->references); */
375         }
376         | SHOW_MESSAGE
377         {
378                 if (msginfo->folder || body) {
379                         gchar buf[BUFFSIZE];
380                         FILE *fp;
381
382                         if (body)
383                                 fp = str_open_as_stream(body);
384                         else
385                                 fp = procmime_get_first_text_content(msginfo);
386
387                         if (fp == NULL)
388                                 g_warning(_("Can't get text part\n"));
389                         else {
390                                 while (fgets(buf, sizeof(buf), fp) != NULL) {
391                                         strcrchomp(buf);
392                                         INSERT(buf);
393                                 }
394                                 fclose(fp);
395                         }
396                 }
397         }
398         | SHOW_QUOTED_MESSAGE
399         {
400                 if (msginfo->folder || body) {
401                         gchar buf[BUFFSIZE];
402                         FILE *fp;
403
404                         if (body)
405                                 fp = str_open_as_stream(body);
406                         else
407                                 fp = procmime_get_first_text_content(msginfo);
408
409                         if (fp == NULL)
410                                 g_warning(_("Can't get text part\n"));
411                         else {
412                                 while (fgets(buf, sizeof(buf), fp) != NULL) {
413                                         strcrchomp(buf);
414                                         if (quote_str)
415                                                 INSERT(quote_str);
416                                         INSERT(buf);
417                                 }
418                                 fclose(fp);
419                         }
420                 }
421         }
422         | SHOW_MESSAGE_NO_SIGNATURE
423         {
424                 if (msginfo->folder || body) {
425                         gchar buf[BUFFSIZE];
426                         FILE *fp;
427
428                         if (body)
429                                 fp = str_open_as_stream(body);
430                         else
431                                 fp = procmime_get_first_text_content(msginfo);
432
433                         if (fp == NULL)
434                                 g_warning(_("Can't get text part\n"));
435                         else {
436                                 while (fgets(buf, sizeof(buf), fp) != NULL) {
437                                         strcrchomp(buf);
438                                         if (strncmp(buf, "-- ", 3) == 0)
439                                                 break;
440                                         INSERT(buf);
441                                 }
442                                 fclose(fp);
443                         }
444                 }
445         }
446         | SHOW_QUOTED_MESSAGE_NO_SIGNATURE
447         {
448                 if (msginfo->folder || body) {
449                         gchar buf[BUFFSIZE];
450                         FILE *fp;
451
452                         if (body)
453                                 fp = str_open_as_stream(body);
454                         else
455                                 fp = procmime_get_first_text_content(msginfo);
456
457                         if (fp == NULL)
458                                 g_warning(_("Can't get text part\n"));
459                         else {
460                                 while (fgets(buf, sizeof(buf), fp) != NULL) {
461                                         strcrchomp(buf);
462                                         if (strncmp(buf, "-- ", 3) == 0)
463                                                 break;
464                                         if (quote_str)
465                                                 INSERT(quote_str);
466                                         INSERT(buf);
467                                 }
468                                 fclose(fp);
469                         }
470                 }
471         }
472         | SHOW_BACKSLASH
473         {
474                 INSERT("\\");
475         }
476         | SHOW_TAB
477         {
478                 INSERT("\t");
479         }
480         | SHOW_EOL
481         {
482                 INSERT("\n");
483         }
484         | SHOW_QUESTION_MARK
485         {
486                 INSERT("?");
487         }
488         | SHOW_PIPE
489         {
490                 INSERT("|");
491         }
492         | SHOW_OPARENT
493         {
494                 INSERT("{");
495         }
496         | SHOW_CPARENT
497         {
498                 INSERT("}");
499         };
500
501 query:
502         QUERY_DATE
503         {
504                 add_visibility(msginfo->date != NULL);
505         }
506         OPARENT quote_fmt CPARENT
507         {
508                 remove_visibility();
509         }
510         | QUERY_FROM
511         {
512                 add_visibility(msginfo->from != NULL);
513         }
514         OPARENT quote_fmt CPARENT
515         {
516                 remove_visibility();
517         }
518         | QUERY_FULLNAME
519         {
520                 add_visibility(msginfo->fromname != NULL);
521         }
522         OPARENT quote_fmt CPARENT
523         {
524                 remove_visibility();
525         }
526         | QUERY_SUBJECT
527         {
528                 add_visibility(msginfo->subject != NULL);
529         }
530         OPARENT quote_fmt CPARENT
531         {
532                 remove_visibility();
533         }
534         | QUERY_TO
535         {
536                 add_visibility(msginfo->to != NULL);
537         }
538         OPARENT quote_fmt CPARENT
539         {
540                 remove_visibility();
541         }
542         | QUERY_NEWSGROUPS
543         {
544                 add_visibility(msginfo->newsgroups != NULL);
545         }
546         OPARENT quote_fmt CPARENT
547         {
548                 remove_visibility();
549         }
550         | QUERY_MESSAGEID
551         {
552                 add_visibility(msginfo->msgid != NULL);
553         }
554         OPARENT quote_fmt CPARENT
555         {
556                 remove_visibility();
557         }
558         | QUERY_CC
559         {
560                 add_visibility(msginfo->cc != NULL);
561         }
562         OPARENT quote_fmt CPARENT
563         {
564                 remove_visibility();
565         }
566         | QUERY_REFERENCES
567         {
568                 /* add_visibility(msginfo->references != NULL); */
569         }
570         OPARENT quote_fmt CPARENT
571         {
572                 remove_visibility();
573         };
574
575 insert:
576         INSERT_FILE OPARENT string CPARENT
577         {
578                 {
579                         FILE *file;
580                         char buffer[256];
581                         
582                         if(file = fopen($3, "rb")) {
583                                 while(fgets(buffer, sizeof(buffer), file)) {
584                                         INSERT(buffer);
585                                 }
586                                 fclose(file);
587                         }
588                 }
589         }
590         | INSERT_PROGRAMOUTPUT OPARENT string CPARENT
591         {
592                 {
593                         FILE *file;
594                         char buffer[256];
595
596                         if(file = popen($3, "r")) {
597                                 while(fgets(buffer, sizeof(buffer), file)) {
598                                         INSERT(buffer);
599                                 }
600                                 fclose(file);
601                         }
602                 }
603         };