16 #define LTRIM(pos) while (isspace(*pos)) { pos++; }
17 #define STRTOLOWER(str, ptr) for (ptr = str ; *ptr ; ptr++) { *ptr = tolower(*ptr); }
23 FILE *fp
; // File pointer
24 long int lastLine
; // Offset of the precedent line (-1 if invalid)
25 long int currentLine
; // Offset of the current line
26 long int messageId
; // Current message Id
27 long int messageBeginning
; // Offset of the beginning of the message (FROM_ line)
29 char *line
; // Line buffer
30 bool isFrom_
; // Is the current line a From_ line ?
36 static MBox
*openMBox(char *filename
)
41 fp
= fopen(filename
, "r");
46 mbox
= (MBox
*)malloc(sizeof(MBox
));
49 mbox
->currentLine
= 0;
51 mbox
->messageBeginning
= 0;
53 mbox
->isFrom_
= false;
59 static void closeMBox(MBox
*mbox
)
71 /** Read a line in a file
73 static char *readLine(MBox
*mbox
)
76 mbox
->lastLine
= mbox
->currentLine
;
77 mbox
->currentLine
= ftell(mbox
->fp
);
78 mbox
->isFrom_
= false;
81 mbox
->line
= (char*)malloc(1001);
83 if (!fgets(mbox
->line
, 1000, mbox
->fp
)) {
84 mbox
->currentLine
= -1;
87 length
= ftell(mbox
->fp
) - mbox
->currentLine
;
92 while (length
>= 0 && (isspace(mbox
->line
[length
]) || mbox
->line
[length
] == '\0')) {
95 mbox
->line
[length
+ 1] = '\0';
97 mbox
->isFrom_
= (strstr(mbox
->line
, "From ") == mbox
->line
);
98 if (mbox
->isFrom_
&& mbox
->messageBeginning
!= mbox
->currentLine
) {
99 mbox
->messageBeginning
= mbox
->currentLine
;
105 #if 0 /* unused right now */
106 /** Return to the last line
108 static bool lastLine(MBox
*mbox
)
110 if (mbox
->lastLine
!= -1) {
111 fseek(mbox
->fp
, mbox
->lastLine
, SEEK_SET
);
120 static bool readFrom_(MBox
*mbox
)
122 if (!mbox
->isFrom_
) {
125 return !!mbox
->isFrom_
;
130 static void readMessage(MBox
*mbox
, bool display
)
132 if (!readFrom_(mbox
)) {
135 while (readLine(mbox
)) {
140 if (strstr(mbox
->line
, ">From ") == mbox
->line
) {
141 puts(mbox
->line
+ 1);
149 /** Read the headers of a message
151 static void readHeaders(MBox
*mbox
, char **headers
, int hdrsize
)
153 char *current
= NULL
;
157 if (!readFrom_(mbox
)) {
160 printf("%d\n%d\n", (int)mbox
->messageId
, (int)mbox
->messageBeginning
);
161 while (readLine(mbox
)) {
162 if (mbox
->isFrom_
|| !strlen(mbox
->line
)) {
165 if (current
&& strlen(mbox
->line
) && isspace(*(mbox
->line
))) {
175 pos
= strchr(mbox
->line
, ':');
176 if (!pos
|| pos
== mbox
->line
) {
179 size
= pos
- mbox
->line
;
180 for (i
= 0 ; i
< hdrsize
; i
++) {
181 if ((int)strlen(headers
[i
]) == size
&& strcasestr(mbox
->line
, headers
[i
]) == mbox
->line
) {
182 current
= (char*)malloc(size
+ 1);
183 strcpy(current
, headers
[i
]);
184 current
[size
] = '\0';
187 if (!current
&& !hdrsize
) {
188 current
= (char*)malloc(size
+ 1);
189 strncpy(current
, mbox
->line
, size
);
190 current
[size
] = '\0';
191 STRTOLOWER(current
, ptr
);
209 /** Go back to the beginning of the file
211 static void rewindMBox(MBox
*mbox
)
213 fseek(mbox
->fp
, 0, SEEK_SET
);
215 mbox
->messageBeginning
= 0;
219 /** Go back to the beginning of the message
221 static bool rewindMessage(MBox
*mbox
)
226 fseek(mbox
->fp
, mbox
->messageBeginning
, SEEK_SET
);
227 mbox
->currentLine
= -1;
230 return mbox
->isFrom_
;
233 /** Move to the given offset
235 static bool goToOffset(MBox
*mbox
, int offset
, int idx
)
237 fseek(mbox
->fp
, offset
, SEEK_SET
);
238 mbox
->currentLine
= -1;
240 mbox
->messageBeginning
= offset
;
241 mbox
->messageId
= idx
;
243 if (!mbox
->isFrom_
) {
249 /** Move to the given message number
251 static bool goToMessage(MBox
*mbox
, int idx
)
253 if (mbox
->messageId
> idx
) {
255 } else if(mbox
->messageId
== idx
) {
258 } else if (!mbox
->isFrom_
) {
259 while (!feof(mbox
->fp
) && !mbox
->isFrom_
) {
262 if (feof(mbox
->fp
)) {
266 while (mbox
->messageId
< idx
&& !feof(mbox
->fp
)) {
267 readMessage(mbox
, false);
269 if (mbox
->messageId
== idx
) {
276 /** Display the program help
278 static void help(void)
280 printf("Usage: mbox-helper [action] [options] -f filename [header1 [header2 ...]]\n"
281 "Actions: only the last action given is applied\n"
282 " -c compute the number of messages. If -p is given, process the file starting à the given offset\n"
283 " -d return the headers of the messages given with the -m option. If no header is given in the\n"
284 " command line options, all the headers are returned. The headers are return with the format:\n"
287 " MSG1_HEADER1_NAME\\n\n"
288 " MSG1_HEADER1_VALUE\\n\n"
289 " MSG1_HEADER2_NAME\\n\n"
290 " MSG2_HEADER2_VALUE\\n\n"
292 " Messages are separated by a blank line\n"
293 " -b return the body of the message given by -m (only 1 message is returned)\n"
295 " -m begin[:end] id or range of messages to process\n"
296 " -p id:pos indicate that message `id` begins at offset `pos`\n"
297 " -h print this help\n");
300 /** Display an error message
301 * This function display the giver error, then show the program help and exit the program
303 static void error(const char *message
)
305 fprintf(stderr
, "Invalid parameters: %s\n", message
);
312 int main(int argc
, char *argv
[])
315 int fmid
= -1, lmid
= -1;
316 int pmid
= 0, pos
= 0;
317 char *filename
= NULL
;
318 char **headers
= NULL
;
324 while ((c
= getopt(argc
, argv
, ":bcdp:hm:f:")) != -1) {
330 fmid
= strtol(optarg
, &endptr
, 10);
331 if (endptr
== optarg
) {
332 error("invalid message id");
334 if (*endptr
!= ':') {
337 lmid
= atoi(endptr
+ 1);
341 if ((endptr
= strchr(optarg
, ':')) != NULL
) {
342 pmid
= strtol(optarg
, &endptr
, 10);
343 if (*endptr
!= ':') {
344 error("invalid position couple given");
346 pos
= atoi(endptr
+ 1);
348 error("invalid position given");
351 case 'c': case 'd': case 'b':
358 fprintf(stderr
, "Missing argument to -%c\n", optopt
);
361 fprintf(stderr
, "Unrecognized option: -%c\n", optopt
);
367 error("no file defined");
370 setlocale(LC_ALL
, "C");
372 headerNb
= argc
- optind
;
373 headers
= (argv
+ optind
);
374 for (i
= 0 ; i
< headerNb
; i
++) {
375 STRTOLOWER(headers
[i
], endptr
);
378 mbox
= openMBox(filename
);
380 fprintf(stderr
, "can't open file '%s'", filename
);
382 if ((fmid
>= pmid
|| fmid
== -1) && pos
) {
383 if (!goToOffset(mbox
, pos
, pmid
)) {
384 fprintf(stderr
, "Offset %d do not match with a message beginning\n", pos
);
391 fprintf(stderr
, "you have to define a message number");
394 goToMessage(mbox
, fmid
);
395 readMessage(mbox
, true);
398 while (!feof(mbox
->fp
)) {
401 printf("%d\n", (int)(mbox
->messageId
+ 1));
405 fprintf(stderr
, "you have to define a message number");
408 for (i
= fmid
; i
<= lmid
; i
++) {
409 goToMessage(mbox
, i
);
410 readHeaders(mbox
, headers
, headerNb
);