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