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