Example #1
0
int main(int argc, char* argv[])
{
	BApplication mailApp(APP_SIG);

	// No arguments, show usage
	if (argc < 2) {
		fprintf(stdout,"This program can only send mail, not read it.\n");
		fprintf(stdout,"usage: %s [-v] [-s subject] [-c cc-addr] "
			"[-b bcc-addr] to-addr ...\n", argv[0]);
		return 0;
	}

	char *subject = "No subject";
	char *cc = "";
	char *bcc = "";
	BString to;
	bool verbose = false;

	// Parse arguments
	for (int i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-v") == 0)
			verbose = true;
		else if (strcmp(argv[i], "-s") == 0) {
			subject = argv[i+1];
			i++;
		} else if (strcmp(argv[i], "-c") == 0) {
			cc = argv[i+1];
			i++;
 		} else if (strcmp(argv[i], "-b") == 0) {
 			bcc = argv[i+1];
 			i++;
		} else {
			if (to.Length() > 0)
				to.Append(", ");
			to.Append(argv[i]);
		}
	}

	if (verbose) {
		fprintf(stdout, "\n");
		fprintf(stdout, "To:\t%s\n", to.String());
		fprintf(stdout, "Cc:\t%s\n", cc);
		fprintf(stdout, "Bcc:\t%s\n", bcc);
		fprintf(stdout, "Subj:\t%s\n", subject);
		fprintf(stdout, "\n");
	}

	// Check if recipients are valid
	if (strcmp(to.String(), "") == 0 &&
		strcmp(cc, "") == 0 &&
		strcmp(bcc, "") == 0) {

		fprintf(stderr, "[Error]: You must specify at least one recipient "
			"in to, cc or bcc fields.\n");
		return -1;
	}

	bool isTerminal = isatty(STDIN_FILENO) != 0;
	if (isTerminal) {
		fprintf(stderr, "Now type your message.\n"
			"Type '.' alone on a line to end your text and send it.\n");
	}

	BString body;
	char line[32768] = "";

	// Read each line and collect the body text until we get an end of text
	// marker.  That's a single dot "." on a line typed in by the user,
	// or end of file when reading a file.
	do {
		if (fgets(line, sizeof(line), stdin) == NULL) {
			// End of file or an error happened, just send collected body text.
			break;
		}

		if (isTerminal && strcmp(line, ".\n") == 0)
			break;

		body.Append(line);
	} while (true);

	if (verbose)
		fprintf(stdout, "\nBody:\n%s\n", body.String());

	if (verbose)
		fprintf(stderr, "Sending E-mail...\n");
	fflush(stdout);

	BMailMessage mail;
	mail.AddHeaderField(B_MAIL_TO, to.String());
	mail.AddHeaderField(B_MAIL_CC, cc);
	mail.AddHeaderField(B_MAIL_BCC, bcc);
	mail.AddHeaderField(B_MAIL_SUBJECT, subject);
	mail.AddContent(body.String(), body.Length());
	status_t result = mail.Send();

	if (result == B_OK) {
		if (verbose)
			fprintf(stderr, "Message was sent successfully.\n");
		return 0;
	}

	fprintf(stderr, "Message failed to send: %s\n", strerror(result));
	return result;
}
bool MailingList::DistributeEmail(IncomingMail* ICMail, std::string ogaddrfilepath)
{
	
	//send ICMail to every address in ogaddrfilepath
	std::vector<std::string> recipients;
	BFile recipientlistbfile;
	status_t filestatus=recipientlistbfile.SetTo(ogaddrfilepath.c_str(),B_READ_ONLY);
	if (filestatus!=B_NO_ERROR)
	{
		LogError("ERROR: Could not read temp file from authentication program - the file could not be opened. Does it exist?");
		return false;	
	}
		off_t bytes; //size of file
		if (recipientlistbfile.GetSize(&bytes) == B_NO_ERROR)
		{
		
			char* buff = new char[bytes];
			off_t bytesread=recipientlistbfile.Read(buff,bytes);
			if (bytesread > 0)
			{
				//file read ok
	
				std::string addr="";
	
				for (int x=0; x < bytesread; x++)
				{
					if (buff[x]!='\n')
					{
						addr=addr+buff[x];
					}
					else
					{
						recipients.push_back(addr);
						addr="";	
					}
				}	
				delete buff;
			}
			else
			{
				LogError("ERROR: Could not read temp file from authentication program - the file was empty");
				delete buff;
				return false;	
			}
		}
		else
		{
			LogError("ERROR: Could not read temp file from authentication program -- could not determine file size");
			return false;	
		}
		
		ICMail->AddSubjectPrefix(fListSubjectPrefix); //fListSubjectPrefix will be null str if not defined in conf file
		ICMail->CleanHeaders(); //clean & setup headers ready for sending message out to recipients
		ICMail->AdjustReplyTo(fForceReplyToList); //set reply to to either sender or list IC address
		
		//if List-Xyz header values were set in conf file we need to set them in msg
		if (fListOwner!="")
		{
			ICMail->SetListOwnerHeader(fListOwner);
		}
		if (fListHelp!="")
		{
			ICMail->SetListHelpHeader(fListHelp);
		}
		if (fListArchive!="")
		{
			ICMail->SetListArchiveHeader(fListArchive);
		}
		if (fListSubscribe!="")
		{
			ICMail->SetListSubscribeHeader(fListSubscribe);
		}
		if (fListUnSubscribe!="")
		{
			ICMail->SetListUnSubscribeHeader(fListUnSubscribe);
		}
	//call GetFromField to get email address in case we need to bounce msg 

	std::string ICsendersAddrField=ICMail->GetSendersAddr(); //returns null string if unable to find
	//at present ICsendersAddrField now has address in form user@domain NOT <user@domain> is this in line with RFC spec?
	


	if (ICMail->CheckIfPlainTextCriteriaPassed(fPlainTextOnly)==false)
	{
		//bounce
		if (fPlainTextOnly=='Y')
		{
				//bounce to sender
				LogError("INFO: Incoming email not text/plain and non plain text messages are not allowed. Bounced to "+ICsendersAddrField);
				BMailMessage* ogmail;
				ogmail= new BMailMessage();
				ogmail->AddHeaderField(B_MAIL_TO,ICsendersAddrField.c_str());
				ogmail->AddHeaderField(B_MAIL_FROM,fListOGEnvelopeAddressFromAddress.c_str());
				std::string bouncesubject=std::string("Undelivered mail: Your message to ");
				bouncesubject=bouncesubject+fListName+" was rejected";
				ogmail->AddHeaderField(B_MAIL_SUBJECT,bouncesubject.c_str());
				std::string xmailer=(fApp->GetAppName())+" mailing list server for Haiku";
				ogmail->AddHeaderField("X-Mailer: ",xmailer.c_str());
				ogmail->AddHeaderField("precedence: ","list");
				std::string bouncecontent="Your message to "+fListName+" was rejected because this list only accepts plain text messages. Make sure your email program is not creating HTML or Rich Text emails and that there are no attached files.";
				bouncecontent=bouncecontent+"\n\nThis is an automated reply sent from the "+fApp->GetAppName()+" for Haiku server at "+fListICAddress;
    			ogmail->AddContent(bouncecontent.c_str(),strlen(bouncecontent.c_str()));
				ogmail->Send();
				delete ogmail;
		}
		else
		{
				//fPlainTextOnly must be 'H'
				//bounce to sender
				LogError("INFO: Incoming email not HTML or plain text and non text messages are not allowed. Bounced to "+ICsendersAddrField);
				BMailMessage* ogmail;
				ogmail= new BMailMessage();
				ogmail->AddHeaderField(B_MAIL_TO,ICsendersAddrField.c_str());
				ogmail->AddHeaderField(B_MAIL_FROM,fListOGEnvelopeAddressFromAddress.c_str());
				std::string bouncesubject=std::string("Undelivered mail: Your message to ");
				bouncesubject=bouncesubject+fListName+" was rejected";
				ogmail->AddHeaderField(B_MAIL_SUBJECT,bouncesubject.c_str());
				std::string xmailer=(fApp->GetAppName())+" mailing list server for Haiku";
				ogmail->AddHeaderField("X-Mailer: ",xmailer.c_str());
				ogmail->AddHeaderField("precedence: ","list");
				std::string bouncecontent="Your message to "+fListName+" was rejected because this list only accepts HTML or plain text messages. Make sure that there are no attached files.";
				bouncecontent=bouncecontent+"\n\nThis is an automated reply sent from the "+fApp->GetAppName()+" for Haiku server at "+fListICAddress;
    			ogmail->AddContent(bouncecontent.c_str(),strlen(bouncecontent.c_str()));
				ogmail->Send();
				delete ogmail;
		}
		return true;
	}

	
	if (ICMail->GetICFileSize() > fMaxContentBytes)
	{
		//msg too big bounce to sender
		LogError("INFO: Incoming email too big. Bounced to "+ICsendersAddrField);
		BMailMessage* ogmail;
		ogmail= new BMailMessage();
		ogmail->AddHeaderField(B_MAIL_TO,ICsendersAddrField.c_str());
		ogmail->AddHeaderField(B_MAIL_FROM,fListOGEnvelopeAddressFromAddress.c_str());
		std::string bouncesubject=std::string("Undelivered mail: Your message to ");
		bouncesubject=bouncesubject+fListName+" was rejected";
		ogmail->AddHeaderField(B_MAIL_SUBJECT,bouncesubject.c_str());
		std::string xmailer=(fApp->GetAppName())+" mailing list server for Haiku";
		ogmail->AddHeaderField("X-Mailer: ",xmailer.c_str());
		ogmail->AddHeaderField("precedence: ","list");
		stringstream converter;
		converter << fMaxContentBytes << " bytes, your message was " << ICMail->GetICFileSize() << " bytes";
		std::string toobigcontent="Your message to "+fListName+" is too big and was rejected. Maximum allowable size for this list is "+converter.str();
		toobigcontent=toobigcontent+"\n\nThis is an automated reply sent from the "+fApp->GetAppName()+" for Haiku server at "+fListICAddress;
    	ogmail->AddContent(toobigcontent.c_str(),strlen(toobigcontent.c_str()));
		ogmail->Send();
		delete ogmail;
		return true;
	}



	//setup a temp file to store the modified og msg
	std::stringstream epochsecs;
	epochsecs << real_time_clock(); //secs now since unix epoch
	int filenamecounterInt=0; //will be incremented until we get a unique filename string
	bool nonuniquefilename=true;
	BEntry tempFileBEntry;
	std::string tempFilePath;
	BFile* tempFileBFile = new BFile();
	do
	{
		filenamecounterInt++;
		std::stringstream filenamecounter;
		filenamecounter << filenamecounterInt;
		tempFilePath=fApp->GetTempDirPath()+fListICAddress+"--"+epochsecs.str()+filenamecounter.str();
		//test if tempFilePath already exists
		tempFileBEntry.SetTo(tempFilePath.c_str());
		status_t tempFileResult=tempFileBFile->SetTo(&tempFileBEntry,B_READ_WRITE|B_FAIL_IF_EXISTS|B_CREATE_FILE); //fails if already exists
		if (tempFileResult==B_FILE_EXISTS)
		{
			nonuniquefilename=true;	
		}
		else if (tempFileResult==B_NO_ERROR)
		{
			nonuniquefilename=false;
			
		}
		else
		{
			//error
			LogError("ERROR: Could not create temp file to store outgoing email");
			return false;
		}
		
	}while(nonuniquefilename);

	//Write modified msg into temp file

	ICMail->WriteToFile(tempFileBFile);



	//store senders addr so we can log it later
	std::string sender="";
	//Send out modified msg in temp file to all recipients
	for (int x=0; x< recipients.size(); x++)
	{
		std::string recipient=recipients[x];
		
		BEmailMessage* ogmail;
		ogmail= new BEmailMessage(tempFileBFile);
    	ogmail->SetTo(recipient.c_str());
    	sender=std::string(ogmail->From());
    	//1st version of send indicates whether to change the From: field to the specified account (requires modified mailkit)
		ogmail->SendViaAccountWithFromPreset(fListOGEnvelopeAddressFromAddress.c_str());
		//ogmail->SendViaAccount(fListOGEnvelopeAddressFromAddress.c_str());
		ogmail->Send(true);
		delete ogmail;
		
	}
	tempFileBFile->Unset(); //close file
	delete tempFileBFile; //delete obj
	//archive msg if needed
	bool archived=false;
	if (fArchivePath!="")
	{
			
			BDirectory dir;
			if ( dir.SetTo(fArchivePath.c_str()) !=B_OK )
			{
				LogError("ERROR: Could not archive message. Check archive folder exists and is writable");
			}
			else
			{
				if ( tempFileBEntry.MoveTo(&dir) !=B_NO_ERROR)
				{
					LogError("ERROR: Could not archive message. Check archive folder exists and is writable");
				}
				else
				{
					archived=true;	
				}
			}
			
	}
	if (archived==false)
	{
		//if archived  then the file was moved so we dont need to delete the original
		tempFileBEntry.Remove();//remove file from filesystem	
	}
	
	stringstream numRecipients;
	numRecipients << recipients.size();
	
	if ( (fLogSuccesses) && (recipients.size()>0)  )
	{
		//if we recipients.size() was 0 sender var is null str as its set in the distribution loop
		LogError("INFO: Successfully distributed an email to "+numRecipients.str()+" recipients from "+sender);
	}
	return true;
}
Example #3
0
int main(int argc, char* argv[])
{
	BApplication mailApp(APP_SIG);

	// No arguments, show usage
	if (argc < 2) {
		fprintf(stdout,"This program can only send mail, not read it.\n");
		fprintf(stdout,"usage: %s [-v] [-s subject] [-c cc-addr] "
			"[-b bcc-addr] to-addr ...\n", argv[0]);
		fflush(stdout);
		return 0;
	}

	char *subject = "No title";
	char *cc = "";
	char *bcc = "";
	BString to = "";
	BString body = "";

	bool verbose =false;
	// Parse arguments
	for (int i = 1; i < argc; i++) {
		if (strcmp(argv[i], "-v") == 0)
			verbose = true;
		else if (strcmp(argv[i], "-s") == 0) {
			subject = argv[i+1];
			i++;
		} else if (strcmp(argv[i], "-c") == 0) {
			cc = argv[i+1];
			i++;
 		} else if (strcmp(argv[i], "-b") == 0) {
 			bcc = argv[i+1];
 			i++;
		} else {
			to.Append(argv[i]);
			if (i < argc - 1)
				to.Append(" ");
  		}
	}

	if (verbose) {
		fprintf(stdout, "\n");
		fprintf(stdout, "To:\t<%s> \n", to.String());
		fprintf(stdout, "Cc:\t<%s> \n", cc);
		fprintf(stdout, "Bcc:\t<%s> \n", bcc);
		fprintf(stdout, "Subj:\t<%s> \n", subject);
		fprintf(stdout, "Body:\t<%s> \n", body.String());
    	fprintf(stdout, "\n");
	}

	// Check if recipients are valid
    if (strcmp(to.String(), "") == 0 &&
    	strcmp(cc, "") == 0 &&
    	strcmp(bcc, "") == 0) {

		fprintf(stdout, "[Error]: You must specify at least one recipient "
			"in to, cc or bcc fields.\n");
		return -1;
	}

	// Read each line until we get a single dot "." on a line
	char line[32768] = "";

	printf("Now type your message.\nType '.' alone on a line to send it.\n");
	do {
	    gets(line);

	    if (strcmp(line, ".") != 0) {
	    	body.Append(line).Append("\n");
		}
	    // fprintf(stdout,"Line: %s \n",line);
	} while (strcmp(line, ".") != 0);


	if (verbose)
   		fprintf(stdout, "\nBody:\n%s\n", body.String());

	if (verbose)
   		fprintf(stdout, "\nSending E-mail...\n");
	fflush(stdout);

	BMailMessage mail;
	mail.AddHeaderField(B_MAIL_TO, to.String());
	mail.AddHeaderField(B_MAIL_CC, cc);
	mail.AddHeaderField(B_MAIL_BCC, bcc);
	mail.AddHeaderField(B_MAIL_SUBJECT, subject);
	mail.AddContent(body.String(), strlen(body.String()));
	status_t result = mail.Send();

	if (result == B_OK) {
		fprintf(stdout, "\nMessage was sent successfully.\n");
		return 0;
	}

	fprintf(stdout, "Message failed to send: %s", strerror(result));
	return result;
}
bool MailingList::ProcessEmailFile(std::string emailfilepathstr)
{
	/*
		Check if sender of email is authorised to post to this list, if not return true and caller will delete file
		else copy it to an outgoing email with relevent header changes, queue og mail for delivery
		and return true so caller will delete file.
		Any errors return false
	*/
	
	
	BFile* bfile = new BFile(emailfilepathstr.c_str(),B_READ_WRITE);
	
	if (bfile->InitCheck() != B_NO_ERROR)
	{
		LogError("ERROR: Could not process an incoming email. BFile::InitCheck was false");
		return false;
	}

	IncomingMail* ICMail= new IncomingMail(bfile,this);
	if (ICMail->InitCheck()==false)
	{
		LogError("ERROR: Could not process an incoming email. File read failed. IncomingMail::InitCheck was false");
		return false;
	}
	
	if (fLogSuccesses)
	{
		LogError("INFO: Processing an email file from "+ICMail->GetSendersAddr());
	}
	
	
	int32 authstatus=1;
	
	/*
		Return vals from external auth prog are 
		0=Authorised
		1=Error
		2=Not Authorsed - bounce msg
		3=Not Authorised - silently discard
		
		This func should return false if val is 1, thus ensuring the incoming file is not deleted and will be re-processed later
		for all other values it should return true, indicating that the incoming file can be deleted
	*/
	int32 arg_c = 4; //no of args passed in arg_v
	extern char **environ; //env variables
	char **arg_v;
	arg_v = (char **) malloc(sizeof(char*) * (arg_c+1)); //array must hold arg_c elements + a terminating null
	
	std::stringstream epochsecs;
	epochsecs << real_time_clock(); //secs now since unix epoch
	int filenamecounterInt=0; //will be incremented until we get a unique filename string
	bool nonuniquefilename=true;
	BEntry tempFileBEntry;
	std::string tempFilePath;
	do
	{
		filenamecounterInt++;
		std::stringstream filenamecounter;
		filenamecounter << filenamecounterInt;
		MailMistressApplication* app=(MailMistressApplication*) be_app;
		tempFilePath=app->GetTempDirPath()+fListICAddress+"--"+ICMail->GetSendersAddr()+"--"+epochsecs.str()+filenamecounter.str();
		//test if tempFilePath already exists
		tempFileBEntry.SetTo(tempFilePath.c_str());
		BFile tempFileBFile;
		status_t tempFileResult=tempFileBFile.SetTo(&tempFileBEntry,B_READ_WRITE|B_FAIL_IF_EXISTS|B_CREATE_FILE); //fails if already exists
		if (tempFileResult==B_FILE_EXISTS)
		{
			nonuniquefilename=true;	
		}
		else if (tempFileResult==B_NO_ERROR)
		{
			nonuniquefilename=false;
			tempFileBFile.Unset(); //close file
		}
		else
		{
			//error
			bfile->Unset();
			//delete ICMail obj
			delete ICMail;
			delete bfile;

			return false;
		}
		
	}while(nonuniquefilename);
	
	
	arg_v[0]=strdup(fAuthProgPath.c_str()); //path to exe
	arg_v[1]=strdup((ICMail->GetSendersAddr()).c_str()); //senders email addr
	arg_v[2]=strdup(tempFilePath.c_str()); //path to temp file
	arg_v[3]=strdup(fListICAddress.c_str()); //list IC address
	arg_v[4]=NULL;
	
	thread_id authprog_team;
	authprog_team=load_image(arg_c,(const char**)arg_v,(const char**)environ);
	free(arg_v);
	wait_for_thread(authprog_team,&authstatus);
	//if authstatus==0 then temp file will now contain all recipient email addresses one per line
	
	if (authstatus==0)
	{
		//send to recipients in temp file
		if (DistributeEmail(ICMail,tempFilePath))
		{
				//delete temp file
				tempFileBEntry.Remove();
				
				//delete ICMail obj
				delete ICMail;
				
				//close orig email file
				bfile->Unset();
				delete bfile;
				return true;
		}
		else
		{
				//delete temp file
				tempFileBEntry.Remove();
				
				//delete ICMail obj
				delete ICMail;
				
				//close orig email file
				bfile->Unset();
				delete bfile;
			
				return false;
		}
	}
	else if (authstatus==2)
	{
			LogError("INFO: Auth status 2 -- Bouncing to "+ICMail->GetSendersAddr());
			BMailMessage* ogmail;
			ogmail= new BMailMessage();
			ogmail->AddHeaderField(B_MAIL_TO,(ICMail->GetSendersAddr()).c_str());
			ogmail->AddHeaderField(B_MAIL_FROM,fListOGEnvelopeAddressFromAddress.c_str());
			std::string bouncesubject=std::string("Undelivered mail: Your message to ");
			bouncesubject=bouncesubject+fListName+" was rejected";
			ogmail->AddHeaderField(B_MAIL_SUBJECT,bouncesubject.c_str());
			ogmail->AddHeaderField("X-Mailer: ",(fApp->GetAppName()).c_str());
    	  	ogmail->AddContent(fUnauthorisedBounceMsgContents.c_str(),strlen(fUnauthorisedBounceMsgContents.c_str()));
			ogmail->Send();
			delete ogmail;
	}
	else if (authstatus==3)
	{
			LogError("INFO: Auth status 3 -- Silently discarding email from "+ICMail->GetSendersAddr());	
			
	}
	
	//delete temp file
	tempFileBEntry.Remove();
	
	if ( (authstatus==2) || (authstatus==3)  )
	{
		//ok so return true to delete incoming file
		delete ICMail;
		bfile->Unset();
		delete bfile;
		
		return true;	
	}
	else
	{
		//error occured so return false and incoming file will be kept for reprocessing later
		LogError("ERROR: Auth status 1 (or other error value). Either the autentication program failed to run or it encountered an error itself");
		delete ICMail;
		bfile->Unset();
		delete bfile;
	
		return false;	
	}
	
}