108c63a2dSAxel Dörfler/*
208c63a2dSAxel Dörfler * Copyright 2005-2009, Haiku Inc.
308c63a2dSAxel Dörfler * This file may be used under the terms of the MIT License.
4667176abSJonas Sundström *
508c63a2dSAxel Dörfler * Originally public domain written by Alexander G. M. Smith.
6667176abSJonas Sundström */
7667176abSJonas Sundström
8667176abSJonas Sundström
908c63a2dSAxel Dörfler/*!	BeMailToMBox is a utility program (requested by Frank Zschockelt) that
1008c63a2dSAxel Dörfler	converts BeOS e-mail files into Unix mailbox files (the kind that Pine
1108c63a2dSAxel Dörfler	uses).  All the files in the input directory are concatenated with the
1208c63a2dSAxel Dörfler	appropriate mbox header lines added between them, and trailing blank lines
1308c63a2dSAxel Dörfler	reduced.  The resulting text is written to standard output.  Command line
1408c63a2dSAxel Dörfler	driven.
1508c63a2dSAxel Dörfler*/
16667176abSJonas Sundström
17667176abSJonas Sundström#include <ctype.h>
18667176abSJonas Sundström#include <errno.h>
1908c63a2dSAxel Dörfler#include <string.h>
2008c63a2dSAxel Dörfler#include <stdio.h>
21667176abSJonas Sundström#include <time.h>
22667176abSJonas Sundström
2308c63a2dSAxel Dörfler#include <Application.h>
2408c63a2dSAxel Dörfler#include <StorageKit.h>
2508c63a2dSAxel Dörfler#include <SupportKit.h>
26667176abSJonas Sundström
2708c63a2dSAxel Dörfler
2808c63a2dSAxel Dörflerextern const char* __progname;
2908c63a2dSAxel Dörflerstatic const char* kProgramName = __progname;
30667176abSJonas Sundström
31cc592ed1SAxel Dörflertime_t gDateStampTime;
32cc592ed1SAxel Dörfler	// Time value used for stamping each message header. Incremented by 1 second
33cc592ed1SAxel Dörfler	// for each message, starts out with the current local time.
34667176abSJonas Sundström
35667176abSJonas Sundström
36cc592ed1SAxel Dörfler/*!	Global utility function to display an error message and return.  The message
37cc592ed1SAxel Dörfler	part describes the error, and if errorNumber is non-zero, gets the string
38cc592ed1SAxel Dörfler	", error code $X (standard description)." appended to it.  If the message
39cc592ed1SAxel Dörfler	is NULL then it gets defaulted to "Something went wrong".
40cc592ed1SAxel Dörfler*/
41cc592ed1SAxel Dörflerstatic void
42cc592ed1SAxel DörflerDisplayErrorMessage(const char* messageString = NULL, status_t errorNumber = 0,
43cc592ed1SAxel Dörfler	const char* titleString = NULL)
44667176abSJonas Sundström{
45cc592ed1SAxel Dörfler	char errorBuffer[2048];
46cc592ed1SAxel Dörfler
47cc592ed1SAxel Dörfler	if (titleString == NULL)
48cc592ed1SAxel Dörfler		titleString = "Error Message:";
49cc592ed1SAxel Dörfler
50cc592ed1SAxel Dörfler	if (messageString == NULL) {
51cc592ed1SAxel Dörfler		if (errorNumber == B_OK)
52cc592ed1SAxel Dörfler			messageString = "No error, no message, why bother?";
53cc592ed1SAxel Dörfler		else
54cc592ed1SAxel Dörfler			messageString = "Error";
55cc592ed1SAxel Dörfler	}
56cc592ed1SAxel Dörfler
57cc592ed1SAxel Dörfler	if (errorNumber != 0) {
5866fa08aaSMurai Takashi		snprintf(errorBuffer, sizeof(errorBuffer), "%s: %s (%" B_PRIx32 ")"
59cc592ed1SAxel Dörfler			"has occured.", messageString, strerror(errorNumber), errorNumber);
6032ebacf2SAxel Dörfler		messageString = errorBuffer;
61cc592ed1SAxel Dörfler	}
62cc592ed1SAxel Dörfler
63cc592ed1SAxel Dörfler	fputs(titleString, stderr);
64cc592ed1SAxel Dörfler	fputc('\n', stderr);
65cc592ed1SAxel Dörfler	fputs(messageString, stderr);
66cc592ed1SAxel Dörfler	fputc('\n', stderr);
67667176abSJonas Sundström}
68667176abSJonas Sundström
69667176abSJonas Sundström
70cc592ed1SAxel Dörfler/*!	Determine if a line of text is the start of another message.  Pine mailbox
71cc592ed1SAxel Dörfler	files have messages that start with a line that could say something like
72cc592ed1SAxel Dörfler	"From agmsmith@achilles.net Fri Oct 31 21:19:36 EST 1997" or maybe something
73cc592ed1SAxel Dörfler	like "From POPmail Mon Oct 20 21:12:36 1997" or in a more modern format,
74cc592ed1SAxel Dörfler	"From agmsmith@achilles.net Tue Sep 4 09:04:11 2001 -0400".  I generalise it
75cc592ed1SAxel Dörfler	to "From blah Day MMM NN XX:XX:XX TZONE1 YYYY TZONE2".  Blah is an e-mail
76cc592ed1SAxel Dörfler	address you can ignore (just treat it as a word separated by spaces).  Day
77cc592ed1SAxel Dörfler	is a 3 letter day of the week.  MMM is a 3 letter month name.  NN is the two
78cc592ed1SAxel Dörfler	digit day of the week, has a leading space if the day is less than 10.
79cc592ed1SAxel Dörfler	XX:XX:XX is the time, the X's are digits.  TZONE1 is the old style optional
80cc592ed1SAxel Dörfler	time zone of 3 capital letters.  YYYY is the four digit year.  TZONE2 is the
81cc592ed1SAxel Dörfler	optional modern time zone info, a plus or minus sign and 4 digits.  Returns
82cc592ed1SAxel Dörfler	true if the line of text (ended with a NUL byte, no line feed or carriage
83cc592ed1SAxel Dörfler	returns at the end) is the start of a message.
84cc592ed1SAxel Dörfler*/
85cc592ed1SAxel Dörflerbool
86cc592ed1SAxel DörflerIsStartOfMailMessage(char* lineString)
87667176abSJonas Sundström{
88cc592ed1SAxel Dörfler	// It starts with "From "
8932ebacf2SAxel Dörfler	if (memcmp("From ", lineString, 5) != 0)
90cc592ed1SAxel Dörfler		return false;
91cc592ed1SAxel Dörfler
92cc592ed1SAxel Dörfler	char* string = lineString + 4;
93cc592ed1SAxel Dörfler	while (*string == ' ')
94cc592ed1SAxel Dörfler		string++;
95cc592ed1SAxel Dörfler
96cc592ed1SAxel Dörfler	// Skip over the e-mail address (or stop at the end of string).
97cc592ed1SAxel Dörfler
98cc592ed1SAxel Dörfler	while (*string != ' ' && *string != 0)
99cc592ed1SAxel Dörfler		string++;
100cc592ed1SAxel Dörfler	while (*string == ' ')
101cc592ed1SAxel Dörfler		string++;
102cc592ed1SAxel Dörfler
103cc592ed1SAxel Dörfler	// TODO: improve this!!!
104cc592ed1SAxel Dörfler
105cc592ed1SAxel Dörfler	// Look for the 3 letter day of the week.
106cc592ed1SAxel Dörfler	if (memcmp(string, "Mon", 3) != 0 && memcmp(string, "Tue", 3) != 0
107cc592ed1SAxel Dörfler		&& memcmp(string, "Wed", 3) != 0 && memcmp(string, "Thu", 3) != 0
108cc592ed1SAxel Dörfler		&& memcmp(string, "Fri", 3) != 0 && memcmp(string, "Sat", 3) != 0
109cc592ed1SAxel Dörfler		&& memcmp(string, "Sun", 3) != 0) {
110cc592ed1SAxel Dörfler		fprintf(stderr, "False alarm, not a valid day of the week in \"%s\""
111cc592ed1SAxel Dörfler			".\n", lineString);
112cc592ed1SAxel Dörfler		return false;
113cc592ed1SAxel Dörfler	}
114cc592ed1SAxel Dörfler
115cc592ed1SAxel Dörfler	string += 3;
116cc592ed1SAxel Dörfler	while (*string == ' ')
117cc592ed1SAxel Dörfler		string++;
118cc592ed1SAxel Dörfler
119cc592ed1SAxel Dörfler	// Look for the 3 letter month code.
120cc592ed1SAxel Dörfler	if (memcmp(string, "Jan", 3) != 0 && memcmp(string, "Feb", 3) != 0
121cc592ed1SAxel Dörfler		&& memcmp(string, "Mar", 3) != 0 && memcmp(string, "Apr", 3) != 0
122cc592ed1SAxel Dörfler		&& memcmp(string, "May", 3) != 0 && memcmp(string, "Jun", 3) != 0
123cc592ed1SAxel Dörfler		&& memcmp(string, "Jul", 3) != 0 && memcmp(string, "Aug", 3) != 0
124cc592ed1SAxel Dörfler		&& memcmp(string, "Sep", 3) != 0 && memcmp(string, "Oct", 3) != 0
125cc592ed1SAxel Dörfler		&& memcmp(string, "Nov", 3) != 0 && memcmp(string, "Dec", 3) != 0) {
126cc592ed1SAxel Dörfler		fprintf(stderr, "False alarm, not a valid month name in \"%s\".\n",
127cc592ed1SAxel Dörfler			lineString);
128cc592ed1SAxel Dörfler		return false;
129cc592ed1SAxel Dörfler	}
130cc592ed1SAxel Dörfler
131cc592ed1SAxel Dörfler	string += 3;
132cc592ed1SAxel Dörfler	while (*string == ' ')
133cc592ed1SAxel Dörfler		string++;
134cc592ed1SAxel Dörfler
135cc592ed1SAxel Dörfler	// Skip the day of the month.  Require at least one digit.
136cc592ed1SAxel Dörfler	if (*string < '0' || *string > '9') {
137cc592ed1SAxel Dörfler		fprintf(stderr, "False alarm, not a valid day of the "
138cc592ed1SAxel Dörfler			"month number in \"%s\".\n", lineString);
139cc592ed1SAxel Dörfler		return false;
140cc592ed1SAxel Dörfler	}
141cc592ed1SAxel Dörfler
142cc592ed1SAxel Dörfler	while (*string >= '0' && *string <= '9')
143cc592ed1SAxel Dörfler		string++;
144cc592ed1SAxel Dörfler	while (*string == ' ')
145cc592ed1SAxel Dörfler		string++;
146cc592ed1SAxel Dörfler
147cc592ed1SAxel Dörfler	// Check the time.  Look for the sequence
148cc592ed1SAxel Dörfler	// digit-digit-colon-digit-digit-colon-digit-digit.
149cc592ed1SAxel Dörfler
150cc592ed1SAxel Dörfler	if (string[0] < '0' || string[0] > '9'
151cc592ed1SAxel Dörfler		|| string[1] < '0' || string[1] > '9'
152cc592ed1SAxel Dörfler		|| string[2] != ':'
153cc592ed1SAxel Dörfler		|| string[3] < '0' || string[3] > '9'
154cc592ed1SAxel Dörfler		|| string[4] < '0' || string[4] > '9'
155cc592ed1SAxel Dörfler		|| string[5] != ':'
156cc592ed1SAxel Dörfler		|| string[6] < '0' || string[6] > '9'
157cc592ed1SAxel Dörfler		|| string[7] < '0' || string[7] > '9') {
158cc592ed1SAxel Dörfler		fprintf(stderr, "False alarm, not a valid time value in \"%s\".\n",
159cc592ed1SAxel Dörfler			lineString);
160cc592ed1SAxel Dörfler		return false;
161cc592ed1SAxel Dörfler	}
162cc592ed1SAxel Dörfler
163cc592ed1SAxel Dörfler	string += 8;
164cc592ed1SAxel Dörfler	while (*string == ' ')
165cc592ed1SAxel Dörfler		string++;
166cc592ed1SAxel Dörfler
167cc592ed1SAxel Dörfler	// Look for the optional antique 3 capital letter time zone and skip it.
168cc592ed1SAxel Dörfler	if (string[0] >= 'A' && string[0] <= 'Z'
169cc592ed1SAxel Dörfler		&& string[1] >= 'A' && string[1] <= 'Z'
170cc592ed1SAxel Dörfler		&& string[2] >= 'A' && string[2] <= 'Z') {
171cc592ed1SAxel Dörfler		string += 3;
172cc592ed1SAxel Dörfler		while (*string == ' ')
173cc592ed1SAxel Dörfler			string++;
174cc592ed1SAxel Dörfler	}
175cc592ed1SAxel Dörfler
176cc592ed1SAxel Dörfler	// Look for the 4 digit year.
177cc592ed1SAxel Dörfler	if (string[0] < '0' || string[0] > '9'
178cc592ed1SAxel Dörfler		|| string[1] < '0' || string[1] > '9'
179cc592ed1SAxel Dörfler		|| string[2] < '0' || string[2] > '9'
180cc592ed1SAxel Dörfler		|| string[3] < '0' || string[3] > '9') {
181cc592ed1SAxel Dörfler		fprintf(stderr, "False alarm, not a valid 4 digit year in \"%s\".\n",
182cc592ed1SAxel Dörfler			lineString);
183cc592ed1SAxel Dörfler		return false;
184cc592ed1SAxel Dörfler	}
185cc592ed1SAxel Dörfler
186cc592ed1SAxel Dörfler	string += 4;
187cc592ed1SAxel Dörfler	while (*string == ' ')
188cc592ed1SAxel Dörfler		string++;
189cc592ed1SAxel Dörfler
190cc592ed1SAxel Dörfler	// Look for the optional modern time zone and skip over it if present.
191cc592ed1SAxel Dörfler	if ((string[0] == '+' || string[0] == '-')
192cc592ed1SAxel Dörfler		&& string[1] >= '0' && string[1] <= '9'
193cc592ed1SAxel Dörfler		&& string[2] >= '0' && string[2] <= '9'
194cc592ed1SAxel Dörfler		&& string[3] >= '0' && string[3] <= '9'
195cc592ed1SAxel Dörfler		&& string[4] >= '0' && string[4] <= '9') {
196cc592ed1SAxel Dörfler		string += 5;
197cc592ed1SAxel Dörfler		while (*string == ' ')
198cc592ed1SAxel Dörfler			string++;
199cc592ed1SAxel Dörfler	}
200cc592ed1SAxel Dörfler
201cc592ed1SAxel Dörfler	// Look for end of string.
202cc592ed1SAxel Dörfler	if (*string != 0) {
203cc592ed1SAxel Dörfler		fprintf(stderr, "False alarm, extra stuff after the "
204cc592ed1SAxel Dörfler			"year/time zone in \"%s\".\n", lineString);
205cc592ed1SAxel Dörfler		return false;
206cc592ed1SAxel Dörfler	}
207cc592ed1SAxel Dörfler
208cc592ed1SAxel Dörfler	return true;
209667176abSJonas Sundström}
210667176abSJonas Sundström
211667176abSJonas Sundström
212cc592ed1SAxel Dörfler/*!	Read the input file, convert it to mbox format, and write it to standard
213cc592ed1SAxel Dörfler	output.  Returns zero if successful, a negative error code if an error
214cc592ed1SAxel Dörfler	occured.
215cc592ed1SAxel Dörfler*/
216cc592ed1SAxel Dörflerstatus_t
217cc592ed1SAxel DörflerProcessMessageFile(char* fileName)
218667176abSJonas Sundström{
219cc592ed1SAxel Dörfler	fprintf(stdout, "Now processing: \"%s\"\n", fileName);
220cc592ed1SAxel Dörfler
221cc592ed1SAxel Dörfler	FILE* inputFile = fopen(fileName, "rb");
222cc592ed1SAxel Dörfler	if (inputFile == NULL) {
223cc592ed1SAxel Dörfler		DisplayErrorMessage("Unable to open file", errno);
224cc592ed1SAxel Dörfler		return errno;
225cc592ed1SAxel Dörfler	}
226cc592ed1SAxel Dörfler
227cc592ed1SAxel Dörfler	// Extract a text message from the Mail file.
228cc592ed1SAxel Dörfler
229cc592ed1SAxel Dörfler	BString messageText;
230cc592ed1SAxel Dörfler	int lineNumber = 0;
231cc592ed1SAxel Dörfler
232cc592ed1SAxel Dörfler	while (!feof(inputFile)) {
233cc592ed1SAxel Dörfler		// First read in one line of text.
234cc592ed1SAxel Dörfler		char line[102400];
235cc592ed1SAxel Dörfler		if (fgets(line, sizeof(line), inputFile) == NULL) {
236cc592ed1SAxel Dörfler			if (ferror(inputFile)) {
237cc592ed1SAxel Dörfler				char errorString[2048];
238cc592ed1SAxel Dörfler				snprintf(errorString, sizeof(errorString),
239cc592ed1SAxel Dörfler					"Error while reading from \"%s\"", fileName);
240cc592ed1SAxel Dörfler				DisplayErrorMessage(errorString, errno);
24132ebacf2SAxel Dörfler				fclose(inputFile);
24232ebacf2SAxel Dörfler				return errno;
243cc592ed1SAxel Dörfler			}
244cc592ed1SAxel Dörfler			break;
245cc592ed1SAxel Dörfler				// No error, just end of file.
246cc592ed1SAxel Dörfler		}
247cc592ed1SAxel Dörfler
248cc592ed1SAxel Dörfler		// Remove any trailing control characters (line feed usually, or CRLF).
249cc592ed1SAxel Dörfler		// Might also nuke trailing tabs too. Doesn't usually matter. The main
250cc592ed1SAxel Dörfler		// thing is to allow input files with both LF and CRLF endings (and
251cc592ed1SAxel Dörfler		// even CR endings if you come from the Macintosh world).
252cc592ed1SAxel Dörfler
253cc592ed1SAxel Dörfler		char* string = line + strlen(line) - 1;
254cc592ed1SAxel Dörfler		while (string >= line && *string < 32)
255cc592ed1SAxel Dörfler			string--;
256cc592ed1SAxel Dörfler		*(++string) = 0;
257cc592ed1SAxel Dörfler
258cc592ed1SAxel Dörfler		if (lineNumber == 0 && line[0] == 0) {
259cc592ed1SAxel Dörfler			// Skip leading blank lines.
260cc592ed1SAxel Dörfler			continue;
261cc592ed1SAxel Dörfler		}
262cc592ed1SAxel Dörfler		lineNumber++;
263cc592ed1SAxel Dörfler
264cc592ed1SAxel Dörfler		// Prepend the new mbox message header, if the first line of the message
265cc592ed1SAxel Dörfler		// doesn't already have one.
266cc592ed1SAxel Dörfler		if (lineNumber == 1 && !IsStartOfMailMessage(line)) {
267cc592ed1SAxel Dörfler			time_t timestamp = gDateStampTime++;
268cc592ed1SAxel Dörfler			messageText.Append("From baron@be.com ");
269cc592ed1SAxel Dörfler			messageText.Append(ctime(&timestamp));
270cc592ed1SAxel Dörfler		}
271cc592ed1SAxel Dörfler
272cc592ed1SAxel Dörfler		// Append the line to the current message text.
273cc592ed1SAxel Dörfler		messageText.Append(line);
274cc592ed1SAxel Dörfler		messageText.Append("\n");
275cc592ed1SAxel Dörfler	}
276cc592ed1SAxel Dörfler
277cc592ed1SAxel Dörfler	// Remove blank lines from the end of the message (a pet peeve of mine), but
278cc592ed1SAxel Dörfler	// end the message with two new lines to separate it from the next message.
279cc592ed1SAxel Dörfler	int i = messageText.Length();
280cc592ed1SAxel Dörfler	while (i > 0 && (messageText[i - 1] == '\n' || messageText[i - 1] == '\r'))
281cc592ed1SAxel Dörfler		i--;
282cc592ed1SAxel Dörfler	messageText.Truncate(i);
283cc592ed1SAxel Dörfler	messageText.Append("\n\n");
284cc592ed1SAxel Dörfler
285cc592ed1SAxel Dörfler	// Write the message out.
28632ebacf2SAxel Dörfler
28732ebacf2SAxel Dörfler	status_t status = B_OK;
28832ebacf2SAxel Dörfler
289cc592ed1SAxel Dörfler	if (puts(messageText.String()) < 0) {
290cc592ed1SAxel Dörfler		DisplayErrorMessage ("Error while writing the message", errno);
291cc592ed1SAxel Dörfler		status = errno;
29232ebacf2SAxel Dörfler	}
293cc592ed1SAxel Dörfler
294cc592ed1SAxel Dörfler	fclose(inputFile);
295cc592ed1SAxel Dörfler	return status;
296667176abSJonas Sundström}
297667176abSJonas Sundström
298667176abSJonas Sundström
299cc592ed1SAxel Dörflerint
300cc592ed1SAxel Dörflermain(int argc, char** argv)
301667176abSJonas Sundström{
302cc592ed1SAxel Dörfler	BApplication app("application/x-vnd.Haiku-mail2mbox");
303cc592ed1SAxel Dörfler
304cc592ed1SAxel Dörfler	if (argc <= 1 || argc >= 3) {
3059563f44bSStephan Aßmus		printf("%s is a utility for converting Mail e-mail\n", argv[0]);
306cc592ed1SAxel Dörfler		printf("files to Unix Pine style e-mail files.  It could well\n");
307cc592ed1SAxel Dörfler		printf("work with other Unix style mailbox files.  Each message in\n");
308cc592ed1SAxel Dörfler		printf("the input directory is converted and sent to the standard\n");
309cc592ed1SAxel Dörfler		printf("output.  Usage:\n\n");
310cc592ed1SAxel Dörfler		printf("%s InputDirectory >OutputFile\n\n", kProgramName);
311cc592ed1SAxel Dörfler		printf("Public domain, by Alexander G. M. Smith.\n");
312cc592ed1SAxel Dörfler		return -10;
313cc592ed1SAxel Dörfler	}
314cc592ed1SAxel Dörfler
315cc592ed1SAxel Dörfler	// Set the date stamp to the current time.
316cc592ed1SAxel Dörfler	gDateStampTime = time (NULL);
317cc592ed1SAxel Dörfler
318cc592ed1SAxel Dörfler	// Try to open the input directory.
319cc592ed1SAxel Dörfler	char inputPathName[B_PATH_NAME_LENGTH];
320cc592ed1SAxel Dörfler	strlcpy(inputPathName, argv[1], sizeof(inputPathName) - 2);
321cc592ed1SAxel Dörfler
322cc592ed1SAxel Dörfler	char tempString[2048];
323cc592ed1SAxel Dörfler
324cc592ed1SAxel Dörfler	DIR* dir = opendir(inputPathName);
325cc592ed1SAxel Dörfler	if (dir == NULL) {
326cc592ed1SAxel Dörfler		sprintf(tempString, "Problems opening directory named \"%s\".",
327cc592ed1SAxel Dörfler			inputPathName);
328cc592ed1SAxel Dörfler		DisplayErrorMessage(tempString, errno);
329cc592ed1SAxel Dörfler		return 1;
330cc592ed1SAxel Dörfler	}
331cc592ed1SAxel Dörfler
332cc592ed1SAxel Dörfler	// Append a trailing slash to the directory name, if it needs one.
33332ebacf2SAxel Dörfler	if (inputPathName[strlen(inputPathName) - 1] != '/')
334cc592ed1SAxel Dörfler		strcat(inputPathName, "/");
335cc592ed1SAxel Dörfler
336cc592ed1SAxel Dörfler	int messagesDoneCount = 0;
337cc592ed1SAxel Dörfler	status_t status = B_OK;
338cc592ed1SAxel Dörfler
339cc592ed1SAxel Dörfler	while (dirent_t* entry = readdir(dir)) {
340cc592ed1SAxel Dörfler		// skip '.' and '..'
341cc592ed1SAxel Dörfler		if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
342cc592ed1SAxel Dörfler			break;
343cc592ed1SAxel Dörfler
344cc592ed1SAxel Dörfler		strlcpy(tempString, inputPathName, sizeof(tempString));
34532ebacf2SAxel Dörfler		strlcat(tempString, entry->d_name, sizeof(tempString));
346cc592ed1SAxel Dörfler
347cc592ed1SAxel Dörfler		status = ProcessMessageFile(tempString);
348cc592ed1SAxel Dörfler		if (status != B_OK)
349cc592ed1SAxel Dörfler			break;
350cc592ed1SAxel Dörfler
351cc592ed1SAxel Dörfler		messagesDoneCount++;
352cc592ed1SAxel Dörfler	}
353cc592ed1SAxel Dörfler
354cc592ed1SAxel Dörfler	closedir(dir);
355cc592ed1SAxel Dörfler
356cc592ed1SAxel Dörfler	if (status != B_OK) {
357cc592ed1SAxel Dörfler		DisplayErrorMessage("Stopping early because an error occured", status);
35832ebacf2SAxel Dörfler		return status;
359cc592ed1SAxel Dörfler	}
360cc592ed1SAxel Dörfler
361cc592ed1SAxel Dörfler	fprintf(stderr, "Did %d messages successfully.\n", messagesDoneCount);
362cc592ed1SAxel Dörfler	return 0;
363667176abSJonas Sundström}