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   char raw_line[BUFFER_SIZE];
71   FILE *file;
72   int in_header;
73
74   file = fopen(input_filename, "r");
75
76   if(!file) {
77     fprintf(stderr, "mymail: Can not open `%s'.\n", input_filename);
78     exit(EXIT_FAILURE);
79   }
80
81   in_header = 0;
82
83   while(fgets(raw_line, BUFFER_SIZE, file)) {
84     if(strncmp(raw_line, "From ", 5) == 0) {
85       if(in_header) {
86         fprintf(stderr, "Got a 'From ' in the header.\n");
87         exit(EXIT_FAILURE);
88       }
89       in_header = 1;
90     } else if(strncmp(raw_line, "\n", 1) == 0) {
91       if(in_header) { in_header = 0; }
92     }
93
94     if(in_header) {
95       printf("LINE.H %s", raw_line);
96     } else {
97       printf("LINE.B %s", raw_line);
98     }
99   }
100
101   fclose(file);
102 }
103
104 int ignore_entry(const char *name) {
105   return
106     strcmp(name, ".") == 0 ||
107     strcmp(name, "..") == 0 ||
108     (name[0] == '.' && name[1] != '/');
109 }
110
111 void process_dir(const char *dir_name) {
112   DIR *dir;
113   struct dirent *dir_e;
114   struct stat sb;
115   char subname[PATH_MAX + 1];
116
117   if(lstat(dir_name, &sb) != 0) {
118     fprintf(stderr, "mymail: Can not stat \"%s\": %s\n", dir_name, strerror(errno));
119     exit(EXIT_FAILURE);
120   } else {
121   }
122
123   if(S_ISLNK(sb.st_mode)) {
124     return;
125   }
126
127   dir = opendir(dir_name);
128
129   if(dir) {
130     printf("Processing directory '%s'.\n", dir_name);
131     while((dir_e = readdir(dir))) {
132       if(!ignore_entry(dir_e->d_name)) {
133         snprintf(subname, PATH_MAX, "%s/%s", dir_name, dir_e->d_name);
134         process_dir(subname);
135       }
136     }
137     closedir(dir);
138   } else {
139     if(S_ISREG(sb.st_mode)) {
140       printf("Processing regular file '%s'.\n", dir_name);
141       read_file(dir_name);
142     }
143   }
144 }
145
146 /*********************************************************************/
147
148 /* For long options that have no equivalent short option, use a
149    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
150 enum
151 {
152   OPT_BASH_MODE = CHAR_MAX + 1
153 };
154
155 static struct option long_options[] = {
156   { "help", no_argument, 0, 'h' },
157   { 0, 0, 0, 0 }
158 };
159
160 int main(int argc, char **argv) {
161   int error = 0, show_help = 0;
162   char c;
163
164   setlocale(LC_ALL, "");
165
166   while ((c = getopt_long(argc, argv, "o:s:x:vwmqf:ibzdeajyunt:r:l:c:-h",
167                           long_options, NULL)) != -1) {
168
169     switch(c) {
170
171     case 'h':
172       show_help = 1;
173       break;
174
175     default:
176       error = 1;
177       break;
178     }
179   }
180
181   if(error) {
182     usage(stderr);
183     exit(EXIT_FAILURE);
184   }
185
186   if(show_help) {
187     usage(stdout);
188     exit(EXIT_SUCCESS);
189   }
190
191   while(optind < argc) {
192     process_dir(argv[optind]);
193     optind++;
194   }
195
196   exit(EXIT_SUCCESS);
197 }