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