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