i3 - improved tiling WM


Add support for mail notification for local maildirs

Patch status: rejected

Patch by Timo Buhrmester

To apply this patch, use:
curl http://cr.i3wm.org/patch/670/raw.patch | git am

b/i3status.c

16
@@ -405,6 +405,18 @@ int main(int argc, char *argv[]) {
17
                 CFG_END()
18
         };
19
 
20
+        cfg_opt_t maildir_opts[] = {
21
+                CFG_STR("format", "%num new %mail", CFGF_NONE), /* format to use when there is new mail */
22
+                CFG_STR("format_nomail", "no mail", CFGF_NONE), /* format to use when there is NO new mail */
23
+                CFG_STR("path", "Maildir", CFGF_NONE), /* Path to maildir, absolute or relative to homedir */
24
+                CFG_STR("name", "INBOX", CFGF_NONE), /* Arbitrary name (for displaying purposes only) */
25
+                CFG_INT("max", 9, CFGF_NONE), /* Max. number of new mails to count (for huge maildirs) */
26
+                CFG_CUSTOM_ALIGN_OPT,
27
+                CFG_CUSTOM_COLOR_OPTS,
28
+                CFG_CUSTOM_MIN_WIDTH_OPT,
29
+                CFG_END()
30
+        };
31
+
32
         cfg_opt_t opts[] = {
33
                 CFG_STR_LIST("order", "{}", CFGF_NONE),
34
                 CFG_SEC("general", general_opts, CFGF_NONE),
35
@@ -416,6 +428,7 @@ int main(int argc, char *argv[]) {
36
                 CFG_SEC("cpu_temperature", temp_opts, CFGF_TITLE | CFGF_MULTI),
37
                 CFG_SEC("disk", disk_opts, CFGF_TITLE | CFGF_MULTI),
38
                 CFG_SEC("volume", volume_opts, CFGF_TITLE | CFGF_MULTI),
39
+                CFG_SEC("maildir", maildir_opts, CFGF_TITLE | CFGF_MULTI),
40
                 CFG_SEC("ipv6", ipv6_opts, CFGF_NONE),
41
                 CFG_SEC("time", time_opts, CFGF_NONE),
42
                 CFG_SEC("tztime", tztime_opts, CFGF_TITLE | CFGF_MULTI),
43
@@ -644,6 +657,13 @@ int main(int argc, char *argv[]) {
44
                                 SEC_CLOSE_MAP;
45
                         }
46
 
47
+                        CASE_SEC_TITLE("maildir") {
48
+                                SEC_OPEN_MAP("maildir");
49
+                                print_maildir(json_gen, buffer, cfg_getstr(sec, "format"), cfg_getstr(sec, "format_nomail"),
50
+                                             cfg_getstr(sec, "path"), cfg_getstr(sec, "name"), cfg_getint(sec, "max"));
51
+                                SEC_CLOSE_MAP;
52
+                        }
53
+
54
                         CASE_SEC_TITLE("cpu_temperature") {
55
                                 SEC_OPEN_MAP("cpu_temperature");
56
                                 print_cpu_temperature_info(json_gen, buffer, atoi(title), cfg_getstr(sec, "path"), cfg_getstr(sec, "format"), cfg_getint(sec, "max_threshold"));

b/include/i3status.h

61
@@ -184,6 +184,7 @@ void print_cpu_usage(yajl_gen json_gen, char *buffer, const char *format);
62
 void print_eth_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down);
63
 void print_load(yajl_gen json_gen, char *buffer, const char *format, const float max_threshold);
64
 void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char *fmt_muted, const char *device, const char *mixer, int mixer_idx);
65
+void print_maildir(yajl_gen json_gen, char *buffer, const char *fmt, const char *fmt_nomail, const char *path, const char *name, int max);
66
 bool process_runs(const char *path);
67
 
68
 /* socket file descriptor for general purposes */

b/src/print_maildir.c

74
@@ -0,0 +1,106 @@
75
+// vim:ts=8:expandtab
76
+#include <time.h>
77
+#include <string.h>
78
+#include <stdbool.h>
79
+#include <stdlib.h>
80
+#include <stdio.h>
81
+#include <yajl/yajl_gen.h>
82
+#include <yajl/yajl_version.h>
83
+
84
+#include <fcntl.h>
85
+#include <unistd.h>
86
+#include <dirent.h>
87
+#include <pwd.h>
88
+
89
+#include "i3status.h"
90
+#include "queue.h"
91
+
92
+void print_maildir(yajl_gen json_gen, char *buffer, const char *fmt, const char *fmt_nomail, const char *path, const char *name, int max) {
93
+        char *outwalk = buffer;
94
+
95
+        if (output_format == O_I3BAR) {
96
+                INSTANCE(path);
97
+        }
98
+
99
+        /* If `path' is relative, look up user's home dir and store in `pathpfx' */
100
+        char pathpfx[128];
101
+        if (path[0] != '/') {
102
+                /* path is relative, look up user's home dir */
103
+                struct passwd *pw = getpwuid(geteuid());
104
+                if (!pw) {
105
+                        fprintf(stderr, "Failed to query user information for uid %d\n", geteuid());
106
+                        return;
107
+                }
108
+
109
+                snprintf(pathpfx, sizeof pathpfx, "%s/", pw->pw_dir);
110
+        } else {
111
+                pathpfx[0] = '\0';
112
+        }
113
+
114
+        char fullpath[512]; /* full path to <maildir>/new */
115
+        snprintf(fullpath, sizeof fullpath, "%s%s/new", pathpfx, path);
116
+
117
+        DIR *d = opendir(fullpath);
118
+        if (!d) {
119
+                fprintf(stderr, "Failed to opendir('%s')\n", fullpath);
120
+                return;
121
+        }
122
+
123
+        /* Count files in 'new', but don't count more than `max' */
124
+        int cnt = -2; /* start w/ -2 because of . and .. */
125
+        bool overmax = false;
126
+        struct dirent *de;
127
+        while ((de = readdir(d))) {
128
+                if (++cnt > max && max) {
129
+                        /* if we have a maximum, stop listing to preserve resources */
130
+                        overmax = true;
131
+                        break;
132
+                }
133
+        }
134
+
135
+        closedir(d);
136
+
137
+        if (!cnt) {
138
+                fmt = fmt_nomail;
139
+        }
140
+
141
+        /* no news is good news */
142
+        START_COLOR(!cnt ? "color_good" : "color_bad");
143
+
144
+        const char *walk = fmt;
145
+        for (; *walk != '\0'; walk++) {
146
+                if (*walk != '%') {
147
+                        *(outwalk++) = *walk;
148
+                        continue;
149
+                }
150
+
151
+                if (BEGINS_WITH(walk+1, "%")) {
152
+                        outwalk += sprintf(outwalk, "%%");
153
+                        walk += strlen("%");
154
+                }
155
+
156
+                /* %num expands to the amount of new mail
157
+                 * However, if `max' is >0, and there are more than `max' new mails, %num expands to `max'+ instead */
158
+                if (BEGINS_WITH(walk+1, "num")) {
159
+                        outwalk += sprintf(outwalk, "%d%s", cnt - overmax, overmax ? "+" : "");
160
+                        walk += strlen("num");
161
+                }
162
+
163
+                /* %mail expands to "mail" or "mails", depending on whether we need singular or plural */
164
+                if (BEGINS_WITH(walk+1, "mail")) {
165
+                        outwalk += sprintf(outwalk, "mail%s", cnt == 1 ? "" : "s");
166
+                        walk += strlen("mail");
167
+                }
168
+
169
+                /* %name expands to the (arbitrary) name specified for this maildir in i3status.conf */
170
+                if (BEGINS_WITH(walk+1, "name")) {
171
+                        outwalk += sprintf(outwalk, "%s", name);
172
+                        walk += strlen("name");
173
+                }
174
+        }
175
+
176
+        *outwalk = '\0';
177
+        OUTPUT_FULL_TEXT(buffer);
178
+
179
+        END_COLOR;
180
+}