8c661f29eebd963e56b4e2949dd1c725504cb869
[apps/madmutt.git] / sidebar.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) ????-2004 Justin Hibbits <jrh29@po.cwru.edu>
4  * Copyright (C) 2004 Thomer M. Gil <mutt@thomer.com>
5  *
6  * Parts were written/modified by:
7  * Rocco Rutte <pdmef@cs.tu-berlin.de>
8  * Nico Golde <nico@ngolde.de>
9  *
10  * This file is part of mutt-ng, see http://www.muttng.org/.
11  * It's licensed under the GNU General Public License,
12  * please see the file GPL in the top level source directory.
13  */
14
15 #include "mutt.h"
16 #include "mutt_menu.h"
17 #include "mutt_curses.h"
18 #include "sidebar.h"
19 #include "buffy.h"
20 #include "keymap.h"
21
22 #include "lib/mem.h"
23 #include "lib/str.h"
24 #include "lib/intl.h"
25
26 #include <libgen.h>
27 #include <ctype.h>
28
29 /*BUFFY *CurBuffy = 0;*/
30 static BUFFY *TopBuffy = 0;
31 static BUFFY *BottomBuffy = 0;
32 static int known_lines = 0;
33 static short initialized = 0;
34 static int prev_show_value;
35 static short saveSidebarWidth;
36 static char *entry = 0;
37
38 static int quick_log10 (int n)
39 {
40   int len = 0;
41
42   for (; n > 9; len++, n /= 10);
43   return (++len);
44 }
45
46 /* CurBuffy should contain a valid buffy 
47  * mailbox before calling this function!!! */
48 void calc_boundaries (int menu)
49 {
50   BUFFY *tmp = Incoming;
51   int position;
52   int i, count, mailbox_position;
53
54   /* correct known_lines if it has changed because of a window resize */
55   if (known_lines != LINES) {
56     known_lines = LINES;
57   }
58   /* fix all the prev links on all the mailboxes
59    * FIXME move this over to buffy.c where it belongs */
60   for (; tmp->next != 0; tmp = tmp->next)
61     tmp->next->prev = tmp;
62
63   /* calculate the position of the current mailbox */
64   position = 1;
65   tmp = Incoming;
66   while (tmp != CurBuffy) {
67     position++;
68     tmp = tmp->next;
69   }
70   /* calculate the size of the screen we can use */
71   count = LINES - 2 - (menu != MENU_PAGER || option (OPTSTATUSONTOP));
72   /* calculate the position of the current mailbox on the screen */
73   mailbox_position = position % count;
74   if (mailbox_position == 0)
75     mailbox_position = count;
76   /* determine topbuffy */
77   TopBuffy = CurBuffy;
78   for (i = mailbox_position; i > 1; i--)
79     TopBuffy = TopBuffy->prev;
80   /* determine bottombuffy */
81   BottomBuffy = CurBuffy;
82   for (i = mailbox_position; i < count && BottomBuffy->next; i++)
83     BottomBuffy = BottomBuffy->next;
84 }
85
86 static char *shortened_hierarchy (char *box)
87 {
88   int dots = 0;
89   char *last_dot;
90   int i, j;
91   char *new_box;
92
93   for (i = 0; i < mutt_strlen (box); ++i) {
94     if (box[i] == '.')
95       ++dots;
96     else if (isupper (box[i]))
97       return (safe_strdup (box));
98   }
99   last_dot = strrchr (box, '.');
100   if (last_dot) {
101     ++last_dot;
102     new_box = safe_malloc (mutt_strlen (last_dot) + 2 * dots + 1);
103     new_box[0] = box[0];
104     for (i = 1, j = 1; i < mutt_strlen (box); ++i) {
105       if (box[i] == '.') {
106         new_box[j++] = '.';
107         new_box[j] = 0;
108         if (&box[i + 1] != last_dot) {
109           new_box[j++] = box[i + 1];
110           new_box[j] = 0;
111         }
112         else {
113           strcat (&new_box[j], last_dot);
114           break;
115         }
116       }
117     }
118     return new_box;
119   }
120   return safe_strdup (box);
121 }
122
123 char *make_sidebar_entry (char *box, int size, int new, int flagged)
124 {
125   int i = 0, dlen, max, shortened = 0;
126   int offset;
127
128   if (SidebarWidth > COLS)
129     SidebarWidth = COLS;
130
131   dlen = mutt_strlen (SidebarDelim);
132   max = SidebarWidth - dlen - 1;
133
134   safe_realloc (&entry, SidebarWidth + 1);
135   entry[SidebarWidth] = 0;
136   for (; i < SidebarWidth; entry[i++] = ' ');
137 #if USE_IMAP
138   if (ImapHomeNamespace && mutt_strlen (ImapHomeNamespace) > 0) {
139     if (strncmp (box, ImapHomeNamespace, mutt_strlen (ImapHomeNamespace)) == 0
140         && strcmp (box, ImapHomeNamespace) != 0) {
141       box += mutt_strlen (ImapHomeNamespace) + 1;
142     }
143   }
144 #endif
145   max -= quick_log10 (size);
146   if (new)
147     max -= quick_log10 (new) + 2;
148   if (flagged > 0)
149     max -= quick_log10 (flagged) + 2;
150   if (option (OPTSHORTENHIERARCHY) && mutt_strlen (box) > max) {
151     box = shortened_hierarchy (box);
152     shortened = 1;
153   }
154   i = mutt_strlen (box);
155   strncpy (entry, box, i < SidebarWidth - dlen ? i : SidebarWidth - dlen);
156
157   if (new) {
158     if (flagged > 0) {
159       offset =
160         SidebarWidth - 5 - quick_log10 (size) - dlen - quick_log10 (new) -
161         quick_log10 (flagged);
162       if (offset < 0)
163         offset = 0;
164       snprintf (entry + offset, SidebarWidth - dlen - offset + 1,
165                 "% d(%d)[%d]", size, new, flagged);
166     }
167     else {
168       offset =
169         SidebarWidth - 3 - quick_log10 (size) - dlen - quick_log10 (new);
170       if (offset < 0)
171         offset = 0;
172       snprintf (entry + offset, SidebarWidth - dlen - offset + 1,
173                 "% d(%d)", size, new);
174     }
175   }
176   else {
177     if (flagged > 0) {
178       offset =
179         SidebarWidth - 3 - quick_log10 (size) - dlen - quick_log10 (flagged);
180       if (offset < 0)
181         offset = 0;
182       snprintf (entry + offset, SidebarWidth - dlen - offset + 1,
183                 "% d[%d]", size, flagged);
184     }
185     else {
186       offset = SidebarWidth - 1 - quick_log10 (size) - dlen;
187       if (offset < 0)
188         offset = 0;
189       snprintf (entry + offset, SidebarWidth - dlen - offset + 1,
190                 "% d", size);
191     }
192   }
193
194   if (option (OPTSHORTENHIERARCHY) && shortened) {
195     free (box);
196   }
197   return entry;
198 }
199
200 void set_curbuffy (char buf[LONG_STRING])
201 {
202   BUFFY *tmp = CurBuffy = Incoming;
203
204   if (!Incoming)
205     return;
206
207   while (1) {
208     if (!mutt_strcmp (tmp->path, buf)) {
209       CurBuffy = tmp;
210       break;
211     }
212
213     if (tmp->next)
214       tmp = tmp->next;
215     else
216       break;
217   }
218 }
219
220 void set_buffystats (CONTEXT * Context)
221 {
222   BUFFY *tmp = Incoming;
223
224   if (!Context)
225     return;
226   while (tmp) {
227     if (mutt_strcmp (tmp->path, Context->path) == 0) {
228       tmp->new = Context->new;
229       tmp->msg_unread = Context->unread;
230       tmp->msgcount = Context->msgcount;
231       tmp->msg_flagged = Context->flagged;
232       break;
233     }
234     tmp = tmp->next;
235   }
236 }
237
238 int draw_sidebar (int menu)
239 {
240
241   int lines = option (OPTHELP) ? 1 : 0;
242   BUFFY *tmp;
243   short delim_len = mutt_strlen (SidebarDelim);
244
245   /* initialize first time */
246   if (!initialized) {
247     prev_show_value = option (OPTMBOXPANE);
248     saveSidebarWidth = SidebarWidth;
249     if (!option (OPTMBOXPANE))
250       SidebarWidth = 0;
251     initialized = 1;
252   }
253
254   /* save or restore the value SidebarWidth */
255   if (prev_show_value != option (OPTMBOXPANE)) {
256     if (prev_show_value && !option (OPTMBOXPANE)) {
257       saveSidebarWidth = SidebarWidth;
258       SidebarWidth = 0;
259     }
260     else if (!prev_show_value && option (OPTMBOXPANE)) {
261       SidebarWidth = saveSidebarWidth;
262       /* after toggle: force recounting of all mail */
263       mutt_buffy_check (2);
264     }
265     prev_show_value = option (OPTMBOXPANE);
266   }
267
268   if (SidebarWidth > 0 && option (OPTMBOXPANE)
269       && mutt_strlen (SidebarDelim) >= SidebarWidth) {
270     mutt_error (_("Value for sidebar_delim is too long. Disabling sidebar."));
271     sleep (2);
272     unset_option (OPTMBOXPANE);
273     return (0);
274   }
275
276   if (SidebarWidth == 0 || !option (OPTMBOXPANE))
277     return 0;
278
279   /* draw the divider */
280   /* SETCOLOR(MT_COLOR_STATUS); */
281   SETCOLOR (MT_COLOR_SIDEBAR);
282   for (lines = 1;
283        lines < LINES - 1 - (menu != MENU_PAGER || option (OPTSTATUSONTOP));
284        lines++) {
285     move (lines, SidebarWidth - delim_len);
286     if (option (OPTASCIICHARS))
287       addstr (NONULL (SidebarDelim));
288     else if (!option (OPTASCIICHARS) && !mutt_strcmp (SidebarDelim, "|"))
289       addch (ACS_VLINE);
290     else if ((Charset_is_utf8) && !mutt_strcmp (SidebarDelim, "|"))
291       addstr ("\342\224\202");
292     else
293       addstr (NONULL (SidebarDelim));
294   }
295   SETCOLOR (MT_COLOR_NORMAL);
296
297   if (Incoming == 0)
298     return 0;
299   lines = option (OPTHELP) ? 1 : 0;     /* go back to the top */
300
301   if (CurBuffy == 0)
302     CurBuffy = Incoming;
303 #if 0
304   if (known_lines != LINES || TopBuffy == 0 || BottomBuffy == 0)
305 #endif
306     calc_boundaries (menu);
307
308   tmp = TopBuffy;
309
310   for (;
311        tmp && lines < LINES - 1 - (menu != MENU_PAGER
312                                    || option (OPTSTATUSONTOP));
313        tmp = tmp->next) {
314     if (tmp == CurBuffy)
315       SETCOLOR (MT_COLOR_INDICATOR);
316     else if (tmp->msg_flagged > 0)
317       SETCOLOR (MT_COLOR_FLAGGED);
318     else if (tmp->msg_unread > 0)
319       SETCOLOR (MT_COLOR_NEW);
320     else
321       SETCOLOR (MT_COLOR_NORMAL);
322
323     move (lines, 0);
324     if (option (OPTSIDEBARNEWMAILONLY)) {
325       if (tmp->msg_unread > 0) {
326         if (Context && !mutt_strcmp (tmp->path, Context->path)) {
327           printw ("%.*s", SidebarWidth - delim_len,
328                   make_sidebar_entry (basename (tmp->path),
329                                       Context->msgcount, Context->unread,
330                                       Context->flagged));
331           tmp->msg_unread = Context->unread;
332           tmp->msgcount = Context->msgcount;
333           tmp->msg_flagged = Context->flagged;
334         }
335         else
336           printw ("%.*s", SidebarWidth - delim_len,
337                   make_sidebar_entry (basename (tmp->path),
338                                       tmp->msgcount, tmp->msg_unread,
339                                       tmp->msg_flagged));
340         lines++;
341       }
342     }
343     else {
344       if (Context && !strcmp (tmp->path, Context->path)) {
345         printw ("%.*s", SidebarWidth - delim_len,
346                 make_sidebar_entry (basename (tmp->path),
347                                     Context->msgcount, Context->unread,
348                                     Context->flagged));
349         tmp->msg_unread = Context->unread;
350         tmp->msgcount = Context->msgcount;
351         tmp->msg_flagged = Context->flagged;
352       }
353       else
354         printw ("%.*s", SidebarWidth - delim_len,
355                 make_sidebar_entry (basename (tmp->path),
356                                     tmp->msgcount, tmp->msg_unread,
357                                     tmp->msg_flagged));
358       lines++;
359     }
360   }
361   SETCOLOR (MT_COLOR_NORMAL);
362   for (; lines < LINES - 1 - (menu != MENU_PAGER || option (OPTSTATUSONTOP));
363        lines++) {
364     int i = 0;
365
366     move (lines, 0);
367     for (; i < SidebarWidth - delim_len; i++)
368       addch (' ');
369   }
370   return 0;
371 }
372
373 BUFFY *exist_next_new ()
374 {
375   BUFFY *tmp = CurBuffy;
376
377   if (tmp == NULL)
378     return NULL;
379   while (tmp->next != NULL) {
380     tmp = tmp->next;
381     if (tmp->msg_unread)
382       return tmp;
383   }
384   return NULL;
385 }
386
387 BUFFY *exist_prev_new ()
388 {
389   BUFFY *tmp = CurBuffy;
390
391   if (tmp == NULL)
392     return NULL;
393   while (tmp->prev != NULL) {
394     tmp = tmp->prev;
395     if (tmp->msg_unread)
396       return tmp;
397   }
398   return NULL;
399 }
400
401
402 void scroll_sidebar (int op, int menu)
403 {
404   BUFFY *tmp;
405
406   if (!SidebarWidth)
407     return;
408   if (!CurBuffy)
409     return;
410
411   switch (op) {
412   case OP_SIDEBAR_NEXT:
413     if (!option (OPTSIDEBARNEWMAILONLY)) {
414       if (CurBuffy->next == NULL) {
415         mutt_error (_("You are on the last mailbox."));
416         return;
417       }
418       CurBuffy = CurBuffy->next;
419       break;
420     }                           /* the fall-through is intentional */
421   case OP_SIDEBAR_NEXT_NEW:
422     if ((tmp = exist_next_new ()) == NULL) {
423       mutt_error (_("No next mailboxes with new mail."));
424       return;
425     }
426     else
427       CurBuffy = tmp;
428     break;
429   case OP_SIDEBAR_PREV:
430     if (!option (OPTSIDEBARNEWMAILONLY)) {
431       if (CurBuffy->prev == NULL) {
432         mutt_error (_("You are on the first mailbox."));
433         return;
434       }
435       CurBuffy = CurBuffy->prev;
436       break;
437     }                           /* the fall-through is intentional */
438   case OP_SIDEBAR_PREV_NEW:
439     if ((tmp = exist_prev_new ()) == NULL) {
440       mutt_error (_("No previous mailbox with new mail."));
441       return;
442     }
443     else
444       CurBuffy = tmp;
445     break;
446
447   case OP_SIDEBAR_SCROLL_UP:
448     CurBuffy = TopBuffy;
449     if (CurBuffy != Incoming) {
450       calc_boundaries (menu);
451       CurBuffy = CurBuffy->prev;
452     }
453     break;
454   case OP_SIDEBAR_SCROLL_DOWN:
455     CurBuffy = BottomBuffy;
456     if (CurBuffy->next) {
457       calc_boundaries (menu);
458       CurBuffy = CurBuffy->next;
459     }
460     break;
461   default:
462     return;
463   }
464   calc_boundaries (menu);
465   draw_sidebar (menu);
466 }