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