Nico Golde:
[apps/madmutt.git] / sidebar.c
1 /*
2  * Copyright (C) ????-2004 Justin Hibbits <jrh29@po.cwru.edu>
3  * Copyright (C) 2004 Thomer M. Gil <mutt@thomer.com>
4  * 
5  *     This program is free software; you can redistribute it and/or modify
6  *     it under the terms of the GNU General Public License as published by
7  *     the Free Software Foundation; either version 2 of the License, or
8  *     (at your option) any later version.
9  * 
10  *     This program is distributed in the hope that it will be useful,
11  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *     GNU General Public License for more details.
14  * 
15  *     You should have received a copy of the GNU General Public License
16  *     along with this program; if not, write to the Free Software
17  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
18  */ 
19
20
21
22 #include "mutt.h"
23 #include "mutt_menu.h"
24 #include "mutt_curses.h"
25 #include "sidebar.h"
26 #include "buffy.h"
27 #include <libgen.h>
28 #include "keymap.h"
29 #include <stdbool.h>
30 #include <ctype.h>
31
32 /*BUFFY *CurBuffy = 0;*/
33 static BUFFY *TopBuffy = 0;
34 static BUFFY *BottomBuffy = 0;
35 static int known_lines = 0;
36 static bool initialized = false;
37 static int prev_show_value;
38 static short saveSidebarWidth;
39 static char *entry = 0;
40
41 static int quick_log10(int n)
42 {
43   int len = 0;
44   for (; n > 9; len++, n /= 10)
45     ;
46   return (++len);
47 }
48
49 // CurBuffy should contain a valid buffy mailbox before calling this function!!!
50 void calc_boundaries (int menu)
51 {
52   BUFFY *tmp = Incoming;
53   int position;
54   int i,count, mailbox_position;
55
56   // correct known_lines if it has changed because of a window resize
57   if ( known_lines != LINES ) {
58     known_lines = LINES;
59   }
60   // fix all the prev links on all the mailboxes
61   for ( ; tmp->next != 0; tmp = tmp->next )
62     tmp->next->prev = tmp;
63
64   // calculate the position of the current mailbox
65   position = 1;
66   tmp = Incoming;
67   while (tmp != CurBuffy)
68   {
69     position++;
70     tmp = tmp->next;
71   }
72   // calculate the size of the screen we can use
73   count = LINES - 2 - (menu != MENU_PAGER || option (OPTSTATUSONTOP));
74   // calculate the position of the current mailbox on the screen
75   mailbox_position = position%count;
76   if (mailbox_position == 0) mailbox_position=count;
77   // determine topbuffy
78   TopBuffy = CurBuffy;
79   for(i = mailbox_position; i >1; i--) TopBuffy = TopBuffy->prev;
80   // determine bottombuffy
81   BottomBuffy = CurBuffy;
82   for(i = mailbox_position; i < count && BottomBuffy->next; i++) BottomBuffy = BottomBuffy->next;
83 }
84
85 static char * shortened_hierarchy(char * box) {
86   int dots = 0;
87   char * last_dot;
88   int i,j;
89   char * new_box;
90   for (i=0;i<strlen(box);++i) {
91     if (box[i] == '.') ++dots;
92     else if (isupper (box[i])) 
93       return (safe_strdup (box));
94   }
95   last_dot = strrchr(box,'.');
96   if (last_dot) {
97     ++last_dot;
98     new_box = safe_malloc(strlen(last_dot)+2*dots+1);
99     new_box[0] = box[0];
100     for (i=1,j=1;i<strlen(box);++i) {
101       if (box[i] == '.') {
102         new_box[j++] = '.';
103         new_box[j] = 0;
104         if (&box[i+1] != last_dot) {
105           new_box[j++] = box[i+1];
106           new_box[j] = 0;
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   char *c;
121   int i = 0, dlen = mutt_strlen (SidebarDelim), max = SidebarWidth-dlen-1,
122       shortened = 0;
123
124   c = realloc(entry, SidebarWidth + 1);
125   if ( c ) entry = c;
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 && strcmp(box,ImapHomeNamespace)!=0) {
131       box+=strlen(ImapHomeNamespace)+1;
132     }
133   }
134 #endif
135   max -= quick_log10(size);
136   if (new)
137     max -= quick_log10(new) + 2;
138   if (flagged > 0)
139     max -= quick_log10(flagged) + 2;
140   if (option(OPTSHORTENHIERARCHY) && mutt_strlen(box) > max) {
141     box = shortened_hierarchy(box);
142     shortened = 1;
143   }
144   i = strlen(box);
145   strncpy( entry, box, i < SidebarWidth - dlen ? i :SidebarWidth - dlen);
146
147   if ( new ) {
148     if (flagged>0) {
149       sprintf(entry + SidebarWidth - 5 - quick_log10(size) - dlen - quick_log10(new) - quick_log10(flagged),
150               "% d(%d)[%d]", size, new, flagged);
151     } else {
152       sprintf(entry + SidebarWidth - 3 - quick_log10(size) - dlen - quick_log10(new),
153               "% d(%d)", size, new);
154     }
155   } else {
156     if (flagged>0) {
157       sprintf( entry + SidebarWidth - 3 - quick_log10(size) - dlen - quick_log10(flagged), "% d[%d]", size,flagged);
158     } else {
159       sprintf( entry + SidebarWidth - 1 - quick_log10(size) - dlen, "% d", size);
160     }
161
162   }
163   if (option(OPTSHORTENHIERARCHY) && shortened) {
164     free(box);
165   }
166   return entry;
167 }
168
169 void set_curbuffy(char buf[LONG_STRING])
170 {
171   BUFFY* tmp = CurBuffy = Incoming;
172
173   if (!Incoming)
174     return;
175
176   while(1) {
177     if(!strcmp(tmp->path, buf)) {
178       CurBuffy = tmp;
179       break;
180     }
181
182     if(tmp->next)
183       tmp = tmp->next;
184     else
185       break;
186   }
187 }
188
189 void set_buffystats (CONTEXT* Context)
190 {
191   BUFFY* tmp = Incoming;
192   if (!Context)
193     return;
194   while (tmp)
195   {
196     if (strcmp (tmp->path, Context->path) == 0)
197     {
198       tmp->msg_unread = Context->unread;
199       tmp->msgcount = Context->msgcount;
200       tmp->msg_flagged = Context->flagged;
201       break;
202     }
203     tmp = tmp->next;
204   }
205 }
206
207 int draw_sidebar(int menu) {
208
209   int lines = option(OPTHELP) ? 1 : 0;
210   BUFFY *tmp;
211   short delim_len = mutt_strlen (SidebarDelim);
212
213   /* initialize first time */
214   if(!initialized) {
215     prev_show_value = option(OPTMBOXPANE);
216     saveSidebarWidth = SidebarWidth;
217     if(!option(OPTMBOXPANE)) SidebarWidth = 0;
218     initialized = true;
219   }
220
221   /* save or restore the value SidebarWidth */
222   if(prev_show_value != option(OPTMBOXPANE)) {
223     if(prev_show_value && !option(OPTMBOXPANE)) {
224       saveSidebarWidth = SidebarWidth;
225       SidebarWidth = 0;
226     } else if(!prev_show_value && option(OPTMBOXPANE)) {
227       SidebarWidth = saveSidebarWidth;
228       /* after toggle: force recounting of all mail */
229       mutt_buffy_check(1);
230     }
231     prev_show_value = option(OPTMBOXPANE);
232   }
233
234   if ( SidebarWidth == 0 ) return 0;
235
236   /* draw the divider */
237   SETCOLOR(MT_COLOR_STATUS);
238   for (lines = option (OPTSTATUSONTOP) ? 0 : 1; 
239        lines < LINES-1-(menu != MENU_PAGER || option (OPTSTATUSONTOP)); lines++ ) {
240     move(lines, SidebarWidth - delim_len);
241     addstr (NONULL (SidebarDelim));
242   }
243   SETCOLOR(MT_COLOR_NORMAL);
244
245   if ( Incoming == 0 ) return 0;
246   lines = option(OPTHELP) ? 1 : 0; /* go back to the top */
247
248   if ( CurBuffy == 0 ) CurBuffy = Incoming;
249   if ( known_lines != LINES || TopBuffy == 0 || BottomBuffy == 0 ) 
250     calc_boundaries(menu);
251
252   tmp = TopBuffy;
253
254   for ( ; tmp && lines < LINES-1 - (menu != MENU_PAGER || option (OPTSTATUSONTOP)); tmp = tmp->next ) {
255     if ( tmp == CurBuffy )
256       SETCOLOR(MT_COLOR_INDICATOR);
257     else if ( tmp->msg_flagged > 0 )
258       SETCOLOR(MT_COLOR_FLAGGED);
259     else if ( tmp->msg_unread > 0 )
260       SETCOLOR(MT_COLOR_NEW);
261     else
262       SETCOLOR(MT_COLOR_NORMAL);
263
264     move( lines, 0 );
265     if ( Context && !strcmp( tmp->path, Context->path ) ) {
266       printw( "%.*s", SidebarWidth - delim_len,
267               make_sidebar_entry(basename(tmp->path),
268                                  Context->msgcount, Context->unread, Context->flagged));
269       tmp->msg_unread = Context->unread;
270       tmp->msgcount = Context->msgcount;
271       tmp->msg_flagged = Context->flagged;
272     }
273     else
274       printw( "%.*s", SidebarWidth - delim_len,
275               make_sidebar_entry(basename(tmp->path),
276                                  tmp->msgcount,tmp->msg_unread, tmp->msg_flagged));
277     lines++;
278   }
279   SETCOLOR(MT_COLOR_NORMAL);
280   for ( ; lines < LINES - 1 - (menu != MENU_PAGER || option (OPTSTATUSONTOP)); lines++ ) {
281     int i = 0;
282     move( lines, 0 );
283     for ( ; i < SidebarWidth - delim_len; i++ )
284       addch(' ');
285   }
286   return 0;
287 }
288
289 BUFFY * exist_next_new()
290 {
291         BUFFY *tmp = CurBuffy;
292         if(tmp == NULL) return NULL;
293         while (tmp->next != NULL)
294         {
295                 tmp = tmp->next;
296                 if(tmp->msg_unread) return tmp;
297         }
298         return NULL;
299 }
300
301 BUFFY * exist_prev_new()
302 {
303         BUFFY *tmp = CurBuffy;
304         if(tmp == NULL) return NULL;
305         while (tmp->prev != NULL)
306         {
307                 tmp = tmp->prev;
308                 if(tmp->msg_unread) return tmp;
309         }
310         return NULL;
311 }     
312
313
314 void scroll_sidebar(int op, int menu)
315 {
316   BUFFY *tmp;
317
318   if(!SidebarWidth) return;
319   if(!CurBuffy) return;
320
321   switch (op) {
322     case OP_SIDEBAR_NEXT:
323       if ( CurBuffy->next == NULL ) return;
324       CurBuffy = CurBuffy->next;
325       break;
326     case OP_SIDEBAR_NEXT_NEW:
327       if ( (tmp = exist_next_new()) == NULL)
328           return;
329       else CurBuffy = tmp;
330       break;
331     case OP_SIDEBAR_PREV:
332       if ( CurBuffy->prev == NULL ) return;
333       CurBuffy = CurBuffy->prev;
334      break;
335     case OP_SIDEBAR_PREV_NEW:
336       if ( (tmp = exist_prev_new()) == NULL)
337           return;
338       else CurBuffy = tmp;
339       break;
340      
341     case OP_SIDEBAR_SCROLL_UP:
342       CurBuffy = TopBuffy;
343       if ( CurBuffy != Incoming ) {
344         calc_boundaries(menu);
345         CurBuffy = CurBuffy->prev;
346       }
347       break;
348     case OP_SIDEBAR_SCROLL_DOWN:
349       CurBuffy = BottomBuffy;
350       if ( CurBuffy->next ) {
351         calc_boundaries(menu);
352         CurBuffy = CurBuffy->next;
353       }
354       break;
355     default:
356       return;
357   }
358   calc_boundaries(menu);
359   draw_sidebar(menu);
360 }