* cleanup for -Wall: unused variables removed, some return types fixed, includes...
[modest] / src / modest-text-utils.c
1 /* modest-ui.c */
2
3 /* insert (c)/licensing information) */
4
5 #include <gtk/gtk.h>
6 #include <string.h>
7 #include <stdlib.h>
8
9 #include "modest-text-utils.h"
10
11
12 #ifdef HAVE_CONFIG_H
13 #include <config.h>
14 #endif /*HAVE_CONFIG_H */
15
16 /* private */
17 static GString *get_next_line (const char *b, const gsize blen, const gchar * iter);
18 static int get_indent_level (const char *l);
19 static void unquote_line (GString * l);
20 static void append_quoted (GString * buf, const int indent,
21                            const GString * str, const int cutpoint);
22 static int get_breakpoint_utf8 (const gchar * s, const gint indent,
23                                 const gint limit);
24 static int get_breakpoint_ascii (const gchar * s, const gint indent,
25                                  const gint limit);
26 static int get_breakpoint (const gchar * s, const gint indent,
27                            const gint limit);
28
29 static GString *
30 get_next_line (const gchar * b, const gsize blen, const gchar * iter)
31 {
32         GString *gs;
33         const gchar *i0;
34         
35         if (iter > b + blen)
36                 return g_string_new("");
37         
38         i0 = iter;
39         while (iter[0]) {
40                 if (iter[0] == '\n')
41                         break;
42                 iter++;
43         }
44         gs = g_string_new_len (i0, iter - i0);
45         return gs;
46 }
47 static int
48 get_indent_level (const char *l)
49 {
50         int indent = 0;
51
52         while (l[0]) {
53                 if (l[0] == '>') {
54                         indent++;
55                         if (l[1] == ' ') {
56                                 l++;
57                         }
58                 } else {
59                         break;
60                 }
61                 l++;
62
63         }
64
65         /*      if we hit the signature marker "-- ", we return -(indent + 1). This
66          *      stops reformatting.
67          */
68         if (strcmp (l, "-- ") == 0) {
69                 return -1 - indent;
70         } else {
71                 return indent;
72         }
73 }
74
75 static void
76 unquote_line (GString * l)
77 {
78         gchar *p;
79
80         p = l->str;
81         while (p[0]) {
82                 if (p[0] == '>') {
83                         if (p[1] == ' ') {
84                                 p++;
85                         }
86                 } else {
87                         break;
88                 }
89                 p++;
90         }
91         g_string_erase (l, 0, p - l->str);
92 }
93
94 static void
95 append_quoted (GString * buf, int indent, const GString * str,
96                const int cutpoint)
97 {
98         int i;
99
100         indent = indent < 0 ? abs (indent) - 1 : indent;
101         for (i = 0; i <= indent; i++) {
102                 g_string_append (buf, "> ");
103         }
104         if (cutpoint > 0) {
105                 g_string_append_len (buf, str->str, cutpoint);
106         } else {
107                 g_string_append (buf, str->str);
108         }
109         g_string_append (buf, "\n");
110 }
111
112 static int
113 get_breakpoint_utf8 (const gchar * s, gint indent, const gint limit)
114 {
115         gint index = 0;
116         const gchar *pos, *last;
117         gunichar *uni;
118
119         indent = indent < 0 ? abs (indent) - 1 : indent;
120
121         last = NULL;
122         pos = s;
123         uni = g_utf8_to_ucs4_fast (s, -1, NULL);
124         while (pos[0]) {
125                 if ((index + 2 * indent > limit) && last) {
126                         g_free (uni);
127                         return last - s;
128                 }
129                 if (g_unichar_isspace (uni[index])) {
130                         last = pos;
131                 }
132                 pos = g_utf8_next_char (pos);
133                 index++;
134         }
135         g_free (uni);
136         return strlen (s);
137 }
138
139 static int
140 get_breakpoint_ascii (const gchar * s, const gint indent, const gint limit)
141 {
142         gint i, last;
143
144         last = strlen (s);
145         if (last + 2 * indent < limit)
146                 return last;
147
148         for (i = strlen (s); i > 0; i--) {
149                 if (s[i] == ' ') {
150                         if (i + 2 * indent <= limit) {
151                                 return i;
152                         } else {
153                                 last = i;
154                         }
155                 }
156         }
157         return last;
158 }
159
160 static int
161 get_breakpoint (const gchar * s, const gint indent, const gint limit)
162 {
163
164         if (g_utf8_validate (s, -1, NULL)) {
165                 return get_breakpoint_utf8 (s, indent, limit);
166         } else {                /* assume ASCII */
167                 //g_warning("invalid UTF-8 in msg");
168                 return get_breakpoint_ascii (s, indent, limit);
169         }
170 }
171
172
173 gchar *
174 modest_text_utils_quote (const gchar * to_quote, const gchar * from,
175                          const time_t sent_date, const int limit)
176 {
177         const gchar *iter;
178         gint indent, breakpoint, rem_indent = 0;
179         gchar sent_str[101];
180         GString *q, *l, *remaining;
181         gsize len;
182
183         /* format sent_date */
184         strftime (sent_str, 100, "%c", localtime (&sent_date));
185         q = g_string_new ("");
186         g_string_printf (q, "On %s, %s wrote:\n", sent_str, from);
187
188         /* remaining will store the rest of the line if we have to break it */
189         remaining = g_string_new ("");
190
191         iter = to_quote;
192         len = strlen(to_quote);
193         do {
194                 l = get_next_line (to_quote, len, iter);
195                 iter = iter + l->len + 1;
196                 indent = get_indent_level (l->str);
197                 unquote_line (l);
198
199                 if (remaining->len) {
200                         if (l->len && indent == rem_indent) {
201                                 g_string_prepend (l, " ");
202                                 g_string_prepend (l, remaining->str);
203                         } else {
204                                 do {
205                                         breakpoint =
206                                                 get_breakpoint (remaining->     str,
207                                                                 rem_indent,
208                                                                 limit);
209                                         append_quoted (q, rem_indent,
210                                                        remaining, breakpoint);
211                                         g_string_erase (remaining, 0,
212                                                         breakpoint);
213                                         if (remaining->str[0] == ' ') {
214                                                 g_string_erase (remaining, 0,
215                                                                 1);
216                                         }
217                                 } while (remaining->len);
218                         }
219                 }
220                 g_string_free (remaining, TRUE);
221                 breakpoint = get_breakpoint (l->str, indent, limit);
222                 remaining = g_string_new (l->str + breakpoint);
223                 if (remaining->str[0] == ' ') {
224                         g_string_erase (remaining, 0, 1);
225                 }
226                 rem_indent = indent;
227                 append_quoted (q, indent, l, breakpoint);
228                 g_string_free (l, TRUE);
229         } while ((iter < to_quote + len) || (remaining->str[0]));
230
231         return g_string_free (q, FALSE);
232 }