Update.
[mymail.git] / mymail.c
1
2 /*
3  *  Copyright (c) 2013 Francois Fleuret
4  *  Written by Francois Fleuret <francois@fleuret.org>
5  *
6  *  This file is part of mymail.
7  *
8  *  mymail is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 3 as
10  *  published by the Free Software Foundation.
11  *
12  *  mymail is distributed in the hope that it will be useful, but
13  *  WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with mymail.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21
22 /*
23
24   To use it as a super-history-search for bash:
25   mymail --bash <(history)
26
27 */
28
29 #define _GNU_SOURCE
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <locale.h>
37 #include <getopt.h>
38 #include <limits.h>
39 #include <dirent.h>
40
41 #define VERSION "0.1"
42
43 #define BUFFER_SIZE 16384
44
45 /********************************************************************/
46
47 /* malloc with error checking.  */
48
49 void *safe_malloc(size_t n) {
50   void *p = malloc(n);
51   if(!p && n != 0) {
52     fprintf(stderr,
53             "mymail: can not allocate memory: %s\n", strerror(errno));
54     exit(EXIT_FAILURE);
55   }
56   return p;
57 }
58
59 /*********************************************************************/
60
61 void usage(FILE *out) {
62   fprintf(out, "mymail version %s (%s)\n", VERSION, UNAME);
63   fprintf(out, "Written by Francois Fleuret <francois@fleuret.org>.\n");
64   fprintf(out, "\n");
65   fprintf(out, "Usage: mymail [options] [<filename1> [<filename2> ...]]\n");
66   fprintf(out, "\n");
67 }
68
69 void read_file(const char *input_filename) {
70
71   char raw_line[BUFFER_SIZE];
72   char *s;
73   FILE *file;
74   int in_header;
75
76   file = fopen(input_filename, "r");
77
78   if(!file) {
79     fprintf(stderr, "mymail: Can not open `%s'.\n", input_filename);
80     exit(EXIT_FAILURE);
81   }
82
83   in_header = 0;
84
85   while(fgets(raw_line, BUFFER_SIZE, file)) {
86     if(strncmp(raw_line, "From ", 5) == 0) {
87       if(in_header) {
88         fprintf(stderr, "Got a 'From ' in the header.\n");
89         exit(EXIT_FAILURE);
90       }
91       in_header = 1;
92     } else if(strncmp(raw_line, "\n", 1) == 0) {
93       if(in_header) { in_header = 0; }
94     }
95
96     if(in_header) {
97       printf("LINE.H %s", raw_line);
98     } else {
99       printf("LINE.B %s", raw_line);
100     }
101   }
102
103   fclose(file);
104 }
105
106 int ignore_entry(const char *name) {
107   return
108     strcmp(name, ".") == 0 ||
109     strcmp(name, "..") == 0 ||
110     (name[0] == '.' && name[1] != '/');
111 }
112
113 void process_dir(const char *dir_name) {
114   DIR *dir;
115   struct dirent *dir_e;
116   struct stat sb;
117   char subname[PATH_MAX + 1];
118
119   if(lstat(dir_name, &sb) != 0) {
120     fprintf(stderr, "mymail: Can not stat \"%s\": %s\n", dir_name, strerror(errno));
121     exit(EXIT_FAILURE);
122   } else {
123   }
124
125   if(S_ISLNK(sb.st_mode)) {
126     return;
127   }
128
129   dir = opendir(dir_name);
130
131   if(dir) {
132     printf("Processing directory '%s'.\n", dir_name);
133     while((dir_e = readdir(dir))) {
134       if(!ignore_entry(dir_e->d_name)) {
135         snprintf(subname, PATH_MAX, "%s/%s", dir_name, dir_e->d_name);
136         process_dir(subname);
137       }
138     }
139     closedir(dir);
140   } else {
141     if(S_ISREG(sb.st_mode)) {
142       printf("Processing regular file '%s'.\n", dir_name);
143       read_file(dir_name);
144     }
145   }
146 }
147
148 /*********************************************************************/
149
150 /* For long options that have no equivalent short option, use a
151    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
152 enum
153 {
154   OPT_BASH_MODE = CHAR_MAX + 1
155 };
156
157 static struct option long_options[] = {
158   { "help", no_argument, 0, 'h' },
159   { 0, 0, 0, 0 }
160 };
161
162 int main(int argc, char **argv) {
163   int error = 0, show_help = 0;
164   char c;
165
166   setlocale(LC_ALL, "");
167
168   while ((c = getopt_long(argc, argv, "o:s:x:vwmqf:ibzdeajyunt:r:l:c:-h",
169                           long_options, NULL)) != -1) {
170
171     switch(c) {
172
173     case 'h':
174       show_help = 1;
175       break;
176
177     default:
178       error = 1;
179       break;
180     }
181   }
182
183   if(error) {
184     usage(stderr);
185     exit(EXIT_FAILURE);
186   }
187
188   if(show_help) {
189     usage(stdout);
190     exit(EXIT_SUCCESS);
191   }
192
193   while(optind < argc) {
194     process_dir(argv[optind]);
195     optind++;
196   }
197
198   exit(EXIT_SUCCESS);
199 }