simplifications around mutt_is_message_type
[apps/madmutt.git] / lib-mime / rfc3676.c
1 /*
2  * Parts were written/modified by:
3  * Andreas Krennmair <ak@synflood.at>
4  * Peter J. Holzer <hjp@hjp.net>
5  * Rocco Rutte <pdmef@cs.tu-berlin.de>
6  *
7  * This file is part of mutt-ng, see http://www.muttng.org/.
8  * It's licensed under the GNU General Public License,
9  * please see the file GPL in the top level source directory.
10  */
11
12 #include <lib-lib/lib-lib.h>
13
14 #include <utime.h>
15
16 #include <lib-ui/curses.h>
17
18 #include "state.h"
19 #include "rfc3676.h"
20
21 #define FLOWED_MAX 77
22
23 static int get_quote_level (char *line)
24 {
25   int quoted;
26
27   for (quoted = 0; line[quoted] == '>'; quoted++);
28   return quoted;
29 }
30
31 static void print_flowed_line (char *line, STATE * s, int ql) {
32   int width;
33   char *pos, *oldpos;
34   int len = m_strlen(line);
35   int i;
36
37   if (MaxLineLength > 0) {
38     width = MaxLineLength - WrapMargin - ql - 1;
39     if (!(s->flags & M_REPLYING) && option (OPTSTUFFQUOTED))
40       --width;
41     if (width < 0)
42       width = MaxLineLength;
43   }
44   else {
45     if (option (OPTMBOXPANE))
46       width = COLS - SidebarWidth - WrapMargin - ql - 1;
47     else
48       width = COLS - WrapMargin - ql - 1;
49
50     if (!(s->flags & M_REPLYING) && option (OPTSTUFFQUOTED))
51       --width;
52     if (width < 0)
53       width = COLS;
54   }
55
56   if (m_strlen(line) == 0) {
57     if (!(s->flags & M_REPLYING) || option (OPTQUOTEEMPTY)) {
58       if (s->prefix)
59         state_puts(s->prefix,s);
60       for (i=0;i<ql;++i) state_putc('>',s);
61       if (!(s->flags & M_REPLYING) && option(OPTSTUFFQUOTED))
62         state_putc(' ',s);
63     }
64     state_putc('\n',s);
65     return;
66   }
67
68   pos = line + width;
69   oldpos = line;
70
71   for (; oldpos < line + len; pos += width) {
72     /* only search a new position when we're not over
73      * the end of the string w/ pos */
74     if (pos < line + len) {
75       if (*pos == ' ') {
76         *pos = '\0';
77         ++pos;
78       }
79       else {
80         char *save = pos;
81
82         while (pos >= oldpos && *pos != ' ') {
83           --pos;
84         }
85         if (pos < oldpos) {
86           pos = save;
87           while (pos < line + len && *pos && *pos != ' ') {
88             ++pos;
89           }
90         }
91         *pos = '\0';
92         ++pos;
93       }
94     }
95
96     if (s->prefix)
97       state_puts (s->prefix, s);
98
99     for (i = 0; i < ql; ++i)
100       state_putc ('>', s);
101     if (!(s->flags & M_REPLYING) && option (OPTSTUFFQUOTED) &&
102         (ql > 0 || s->prefix))
103       state_putc (' ', s);
104     state_puts (oldpos, s);
105     /* fprintf(stderr,"print_flowed_line: `%s'\n",oldpos); */
106     if (pos < line + len)
107       state_putc (' ', s);
108     state_putc ('\n', s);
109     oldpos = pos;
110   }
111 }
112
113 int rfc3676_handler (BODY * a, STATE * s) {
114   int bytes = a->length;
115   char buf[LONG_STRING];
116   char *curline = p_new(char, 1);
117   char *t = NULL;
118   unsigned int curline_len = 1,
119                quotelevel = 0, newql = 0;
120   int buf_off, buf_len;
121   int delsp = 0, fixed = 0;
122
123   *curline='\0';
124
125   /* respect DelSP of RfC3676 only with f=f parts */
126   if ((t = parameter_getval(a->parameter, "delsp"))) {
127     delsp = m_strlen(t) == 3 && ascii_strncasecmp (t, "yes", 3) == 0;
128     t = NULL;
129   }
130
131
132   while (bytes > 0 && fgets (buf, sizeof (buf), s->fpin)) {
133
134     buf_len = m_strlen(buf);
135     bytes -= buf_len;
136
137     newql = get_quote_level (buf);
138
139     /* a change of quoting level in a paragraph - shouldn't happen, 
140      * but has to be handled - see RFC 3676, sec. 4.5.
141      */
142     if (newql != quotelevel && curline && *curline) {
143       print_flowed_line (curline, s, quotelevel);
144       *curline = '\0';
145       curline_len = 1;
146     }
147     quotelevel = newql;
148
149     /* XXX - If a line is longer than buf (shouldn't happen), it is split.
150      * This will almost always cause an unintended line break, and 
151      * possibly a change in quoting level. But that's better than not
152      * displaying it at all.
153      */
154     if ((t = strrchr (buf, '\r')) || (t = strrchr (buf, '\n'))) {
155       *t = '\0';
156       buf_len = t - buf;
157     }
158
159     buf_off = newql;
160     /* respect space-stuffing */
161     if (buf[buf_off] == ' ')
162       buf_off++;
163
164     /* for DelSp=yes, we need to strip one SP prior to CRLF
165      * which may make the line look like fixed although it wasn't
166      * so keep this in mind for later processing */
167     fixed = buf_len == 0 || buf[buf_len - 1] != ' ' ||
168             (m_strcmp(buf + buf_off, "-- ") == 0);
169
170     if (delsp && buf_len >= 1 && buf[buf_len-1] == ' ')
171       buf[--buf_len] = '\0';
172
173     /* we're here when last space removed 'cause of DelSp was
174      * the last space and there isn't more -> done */
175     if ((buf_len - buf_off) < 0) {
176       print_flowed_line (curline, s, quotelevel);
177       *curline = '\0';
178       curline_len = 1;
179       continue;
180     }
181
182     /* signature separator also flushes the previous paragraph */
183     if (m_strcmp(buf + buf_off, "-- ") == 0 && curline && *curline) {
184       print_flowed_line (curline, s, quotelevel);
185       *curline = '\0';
186       curline_len = 1;
187     }
188
189     p_realloc(&curline, curline_len + buf_len - buf_off);
190     m_strcpy(curline + curline_len - 1, buf_len - buf_off + 1, buf + buf_off);
191     curline_len += buf_len - buf_off;
192
193     /* if this was a fixed line the paragraph is finished */
194     if (fixed) {
195       print_flowed_line (curline, s, quotelevel);
196       *curline = '\0';
197       curline_len = 1;
198     }
199
200   }
201   p_delete(&curline);
202   return (0);
203 }
204
205 /* sets mtime of 'to' to mtime of 'from' */
206 static void mutt_set_mtime (const char* from, const char* to) {
207   struct utimbuf utim;
208   struct stat st;
209
210   if (stat (from, &st) != -1) {
211     utim.actime = st.st_mtime;
212     utim.modtime = st.st_mtime;
213     utime (to, &utim);
214   }
215 }
216
217 void rfc3676_space_stuff (HEADER* hdr) {
218   FILE* in = NULL, *out = NULL;
219   char buf[LONG_STRING];
220   char tmpf[_POSIX_PATH_MAX];
221
222   if (!hdr || !hdr->content || !hdr->content->filename)
223     return;
224
225   if ((in = safe_fopen (hdr->content->filename, "r")) == NULL)
226     return;
227
228   out = m_tempfile(tmpf, sizeof(tmpf), NONULL(Tempdir), NULL);
229   if (!out) {
230     m_fclose(&in);
231     return;
232   }
233
234   while (fgets(buf, sizeof (buf), in)) {
235     if (m_strncmp("From ", buf, 4) == 0 || buf[0] == ' ') {
236       fputc (' ', out);
237     }
238     fputs (buf, out);
239   }
240   m_fclose(&in);
241   m_fclose(&out);
242   mutt_set_mtime (hdr->content->filename, tmpf);
243   unlink (hdr->content->filename);
244   m_strreplace(&hdr->content->filename, tmpf);
245 }