anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

mail.cpp (4851B)

      1 /*
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  *
      8  * Based on the original code of Epona by Lara.
      9  * Based on the original code of Services by Andy Church.
     10  */
     11 
     12 #include "services.h"
     13 #include "mail.h"
     14 #include "config.h"
     15 
     16 Mail::Message::Message(const Anope::string &sf, const Anope::string &mailto, const Anope::string &a, const Anope::string &s, const Anope::string &m) : Thread(), sendmail_path(Config->GetBlock("mail")->Get<const Anope::string>("sendmailpath")), send_from(sf), mail_to(mailto), addr(a), subject(s), message(m), dont_quote_addresses(Config->GetBlock("mail")->Get<bool>("dontquoteaddresses")), success(false)
     17 {
     18 }
     19 
     20 Mail::Message::~Message()
     21 {
     22 	if (success)
     23 		Log(LOG_NORMAL, "mail") << "Successfully delivered mail for " << mail_to << " (" << addr << ")";
     24 	else
     25 		Log(LOG_NORMAL, "mail") << "Error delivering mail for " << mail_to << " (" << addr << ")";
     26 }
     27 
     28 void Mail::Message::Run()
     29 {
     30 	FILE *pipe = popen(sendmail_path.c_str(), "w");
     31 
     32 	if (!pipe)
     33 	{
     34 		SetExitState();
     35 		return;
     36 	}
     37 
     38 	fprintf(pipe, "From: %s\n", send_from.c_str());
     39 	if (this->dont_quote_addresses)
     40 		fprintf(pipe, "To: %s <%s>\n", mail_to.c_str(), addr.c_str());
     41 	else
     42 		fprintf(pipe, "To: \"%s\" <%s>\n", mail_to.c_str(), addr.c_str());
     43 	fprintf(pipe, "Subject: %s\n", subject.c_str());
     44 	fprintf(pipe, "Content-Type: text/plain; charset=UTF-8;\n");
     45 	fprintf(pipe, "Content-Transfer-Encoding: 8bit\n");
     46 	fprintf(pipe, "\n");
     47 	fprintf(pipe, "%s", message.c_str());
     48 	fprintf(pipe, "\n.\n");
     49 
     50 	pclose(pipe);
     51 
     52 	success = true;
     53 	SetExitState();
     54 }
     55 
     56 bool Mail::Send(User *u, NickCore *nc, BotInfo *service, const Anope::string &subject, const Anope::string &message)
     57 {
     58 	if (!nc || !service || subject.empty() || message.empty())
     59 		return false;
     60 
     61 	Configuration::Block *b = Config->GetBlock("mail");
     62 
     63 	if (!u)
     64 	{
     65 		if (!b->Get<bool>("usemail") || b->Get<const Anope::string>("sendfrom").empty())
     66 			return false;
     67 		else if (nc->email.empty())
     68 			return false;
     69 
     70 		nc->lastmail = Anope::CurTime;
     71 		Thread *t = new Mail::Message(b->Get<const Anope::string>("sendfrom"), nc->display, nc->email, subject, message);
     72 		t->Start();
     73 		return true;
     74 	}
     75 	else
     76 	{
     77 		if (!b->Get<bool>("usemail") || b->Get<const Anope::string>("sendfrom").empty())
     78 			u->SendMessage(service, _("Services have been configured to not send mail."));
     79 		else if (Anope::CurTime - u->lastmail < b->Get<time_t>("delay"))
     80 			u->SendMessage(service, _("Please wait \002%d\002 seconds and retry."), b->Get<time_t>("delay") - (Anope::CurTime - u->lastmail));
     81 		else if (nc->email.empty())
     82 			u->SendMessage(service, _("E-mail for \002%s\002 is invalid."), nc->display.c_str());
     83 		else
     84 		{
     85 			u->lastmail = nc->lastmail = Anope::CurTime;
     86 			Thread *t = new Mail::Message(b->Get<const Anope::string>("sendfrom"), nc->display, nc->email, subject, message);
     87 			t->Start();
     88 			return true;
     89 		}
     90 
     91 		return false;
     92 	}
     93 }
     94 
     95 bool Mail::Send(NickCore *nc, const Anope::string &subject, const Anope::string &message)
     96 {
     97 	Configuration::Block *b = Config->GetBlock("mail");
     98 	if (!b->Get<bool>("usemail") || b->Get<const Anope::string>("sendfrom").empty() || !nc || nc->email.empty() || subject.empty() || message.empty())
     99 		return false;
    100 
    101 	nc->lastmail = Anope::CurTime;
    102 	Thread *t = new Mail::Message(b->Get<const Anope::string>("sendfrom"), nc->display, nc->email, subject, message);
    103 	t->Start();
    104 
    105 	return true;
    106 }
    107 
    108 /**
    109  * Checks whether we have a valid, common e-mail address.
    110  * This is NOT entirely RFC compliant, and won't be so, because I said
    111  * *common* cases. ;) It is very unlikely that e-mail addresses that
    112  * are really being used will fail the check.
    113  *
    114  * @param email Email to Validate
    115  * @return bool
    116  */
    117 bool Mail::Validate(const Anope::string &email)
    118 {
    119 	bool has_period = false;
    120 
    121 	static char specials[] = {'(', ')', '<', '>', '@', ',', ';', ':', '\\', '\"', '[', ']', ' '};
    122 
    123 	if (email.empty())
    124 		return false;
    125 	Anope::string copy = email;
    126 
    127 	size_t at = copy.find('@');
    128 	if (at == Anope::string::npos)
    129 		return false;
    130 	Anope::string domain = copy.substr(at + 1);
    131 	copy = copy.substr(0, at);
    132 
    133 	/* Don't accept empty copy or domain. */
    134 	if (copy.empty() || domain.empty())
    135 		return false;
    136 
    137 	/* Check for forbidden characters in the name */
    138 	for (unsigned i = 0, end = copy.length(); i < end; ++i)
    139 	{
    140 		if (copy[i] <= 31 || copy[i] >= 127)
    141 			return false;
    142 		for (unsigned int j = 0; j < 13; ++j)
    143 			if (copy[i] == specials[j])
    144 				return false;
    145 	}
    146 
    147 	/* Check for forbidden characters in the domain */
    148 	for (unsigned i = 0, end = domain.length(); i < end; ++i)
    149 	{
    150 		if (domain[i] <= 31 || domain[i] >= 127)
    151 			return false;
    152 		for (unsigned int j = 0; j < 13; ++j)
    153 			if (domain[i] == specials[j])
    154 				return false;
    155 		if (domain[i] == '.')
    156 		{
    157 			if (!i || i == end - 1)
    158 				return false;
    159 			has_period = true;
    160 		}
    161 	}
    162 
    163 	return has_period;
    164 }