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