Files
secondo/Algebras/Mail/MailAlgebra.cpp

1069 lines
23 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
----
This file is part of SECONDO.
Copyright (C) 2008, University in Hagen,
Faculty of Mathematics and Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
//paragraph [1] Title: [{\Large \bf \begin{center}] [\end{center}}]
//paragraph [10] Footnote: [{\footnote{] [}}]
//[ue] [\"u]
//[ae] [\"a]
//[_] [\_]
//[TOC] [\tableofcontents]
[1] MailAlgebra
This algebra provides Mail functions for different
purposes.
*/
/*
[TOC]
1 Overview
This file contains the implementation import / export operators.
2 Defines, includes, and constants
*/
#include <cmath>
#include <stack>
#include <limits>
#include <sstream>
#include <vector>
#include <fstream>
#include <sys/stat.h>
#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include "SocketIO.h"
#include "NestedList.h"
#include "QueryProcessor.h"
#include "AlgebraManager.h"
#include "Algebra.h"
#include "StandardTypes.h"
#include "Algebras/Relation-C++/RelationAlgebra.h"
#include "SecondoSystem.h"
#include "Algebras/FText/FTextAlgebra.h"
#include "Tools/Flob/DbArray.h"
#include "Symbols.h"
#include "FileSystem.h"
#include "ListUtils.h"
#include "Attribute.h"
#include "StringUtils.h"
#include "version.h"
#include "Stream.h"
#include <string>
extern NestedList* nl;
extern QueryProcessor* qp;
extern AlgebraManager* am;
#define FILE_BUFFER_SIZE 1048576
using namespace std;
/*
1 Operator ~sendmail~
1.1 Type Mapping for ~sendmail~
*/
ListExpr sendmailtypemap( ListExpr args )
{
if(!nl->HasLength(args,5))
{
return listutils::typeError("five arguments expected");
}
ListExpr arg1 = nl->First(args);
ListExpr arg2 = nl->Second(args);
ListExpr arg3 = nl->Third(args);
ListExpr arg4 = nl->Fourth(args);
ListExpr arg5 = nl->Fifth(args);
if((!FText::checkType(arg1)) || (!FText::checkType(arg2))
|| (!FText::checkType(arg3)) || (!FText::checkType(arg4))
|| (!FText::checkType(arg5)) )
{
return listutils::typeError("all arguments must have a FText value");
}
return nl->SymbolAtom(CcBool::BasicType());
}
/*
2 Operator ~embedTags~
121 Type Mapping for ~embedTags~
*/
ListExpr embedTagstypemap( ListExpr args )
{
if(nl->ListLength(args)!=4){
ErrorReporter::ReportError("four elements expected");
return nl->TypeError();
}
ListExpr stream = nl->First(args);
if(!IsStreamDescription(stream)){
ErrorReporter::ReportError("first argument is not a tuple stream");
return nl->TypeError();
}
ListExpr first = nl->Second(args);
ListExpr second = nl->Third(args);
ListExpr third = nl->Fourth(args);
if( (nl->ListLength(first) != -1) || (nl->ListLength(second) != -1 )
|| (nl->ListLength(third) != -1) )
{
ErrorReporter::ReportError("three attribute name arguments expected");
return nl->TypeError();
}
if (!listutils::isSymbol(first)) {
return listutils::typeError("Second argument must be an attribute name");
}
if (!listutils::isSymbol(second)) {
return listutils::typeError("Third argument must be an attribute name");
}
if (!listutils::isSymbol(third)) {
return listutils::typeError("Fourth argument must be an attribute name");
}
// copy attrlist to newattrlist
ListExpr attrList = nl->Second(nl->Second(stream));
ListExpr newAttrList = nl->OneElemList(nl->First(attrList));
ListExpr lastlistn = newAttrList;
attrList = nl->Rest(attrList);
while (!(nl->IsEmpty(attrList)))
{
lastlistn = nl->Append(lastlistn,nl->First(attrList));
attrList = nl->Rest(attrList);
}
// reset attrList
attrList = nl->Second(nl->Second(stream));
ListExpr attrtype;
// check argues
ListExpr firstname, secondname, thirdname;
string firstnamestr, secondnamestr, thirdnamestr;
int posit, posit2, posit3;
ListExpr typea, typeb;
if (nl->AtomType(first) == SymbolType)
{
firstname = first;
firstnamestr = nl->SymbolValue(firstname);
}
else
{
ErrorReporter::ReportError
("Attributename in the list is not of symbol type.");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (nl->AtomType(second) == SymbolType)
{
secondname = second;
secondnamestr = nl->SymbolValue(secondname);
}
else
{
ErrorReporter::ReportError
("Attributename in the list is not of symbol type.");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
if (nl->AtomType(third) == SymbolType)
{
thirdname = third;
thirdnamestr = nl->SymbolValue(thirdname);
}
else {
ErrorReporter::ReportError
("Attributename in the list is not of symbol type.");
return nl->SymbolAtom(Symbol::TYPEERROR());
}
posit2 = FindAttribute(attrList,secondnamestr,attrtype);
if(posit2!=0){
ErrorReporter::ReportError("Attribute "+ secondnamestr +
" is already a member of the tuple");
return nl->TypeError();
}
posit3 = FindAttribute(attrList,thirdnamestr,attrtype);
if(posit3!=0){
ErrorReporter::ReportError("Attribute "+ thirdnamestr +
" is already a member of the tuple");
return nl->TypeError();
}
posit = FindAttribute(attrList,firstnamestr,attrtype);
if(posit==0){
ErrorReporter::ReportError("Attribute "+ firstnamestr +
" must be a member of the tuple");
return nl->TypeError();
}
if (!FText::checkType(attrtype)) {
return listutils::typeError
("Attribute" + firstnamestr+ " must have a FText value");
}
typea = nl->SymbolAtom(CcBool::BasicType());
typeb = nl->SymbolAtom(FText::BasicType());
// append attribute
lastlistn = nl->Append(lastlistn, (nl->TwoElemList(secondname, typeb)));
lastlistn = nl->Append(lastlistn, (nl->TwoElemList(thirdname, typea)));
return
nl->ThreeElemList(
nl->SymbolAtom(Symbol::APPEND()),
nl->OneElemList(nl->IntAtom(posit)),
nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()),
nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()),newAttrList)));
}
/*
1.2 Value Mapping for ~sendmail~
*/
int sendmailVM(Word* args, Word& result,
int message, Word& local, Supplier s)
{
FText* firstargsub = static_cast<FText*>(args[0].addr);
FText* secondargsender = static_cast<FText*>(args[1].addr);
FText* thirdargadress = static_cast<FText*>(args[2].addr);
FText* fourthargmessage = static_cast<FText*>(args[3].addr);
FText* fifthargmessage = static_cast<FText*>(args[4].addr);
result = qp->ResultStorage(s);
CcBool* b = static_cast<CcBool*>( result.addr );
bool res = false;
if((!firstargsub->IsDefined()) || (! secondargsender->IsDefined())
|| (! thirdargadress->IsDefined()) || (! fourthargmessage->IsDefined())
|| (! fifthargmessage->IsDefined()) )
{
b->SetDefined(false);
return 0;
}
//constructing the postfix call
string sub = firstargsub->GetValue();
string sdr = secondargsender->GetValue();
string adr = thirdargadress->GetValue();
string msg = fourthargmessage->GetValue();
string cbc = fifthargmessage->GetValue();
string subpart1 = "mail -s '";
string subpart2 = "' -r ";
string subpart3 = " <<< '";
string subpart4 = " ";
string subpart5 = "'";
string subpart6 = " -c ";
string finalcall = "";
string call = subpart1 + sub + subpart2 + sdr +
subpart4 + adr + subpart3 + msg + subpart5;
string callcarbcopy = subpart1 + sub + subpart2 + sdr + subpart6 +
cbc + subpart4 + adr + subpart3 + msg + subpart5;
if (cbc.empty())
{
finalcall = call;
}
else {
finalcall= callcarbcopy;
}
//checking if mail adress has some syntax errors
const char * cll1 = finalcall.c_str();
int back1 = 0;
size_t at1 = sdr.find('@');
size_t at2 = adr.find('@');
size_t at3 = cbc.find('@');
size_t dot1 = sdr.find('.', at1 + 1);
size_t dot2 = adr.find('.', at2 + 1);
size_t dot3 = cbc.find('.', at3 + 1);
size_t count1 = std::count(sdr.begin(), sdr.end(), '@');
size_t count2 = std::count(adr.begin(), adr.end(), '@');
size_t count7 = std::count(cbc.begin(), cbc.end(), '@');
size_t count3 = std::count(sdr.begin(), sdr.end(), ':');
size_t count4 = std::count(adr.begin(), adr.end(), ':');
size_t count8 = std::count(cbc.begin(), cbc.end(), ':');
size_t count5 = std::count(sdr.begin(), sdr.end(), '/');
size_t count6 = std::count(adr.begin(), adr.end(), '/');
size_t count9 = std::count(cbc.begin(), cbc.end(), '/');
if (!(cbc.empty()))
{
if ( (count1 == 1) && (count2 == 1) && (count7 == 1)
&& (!((dot1 == string::npos)
|| (dot2 == string::npos) || (dot3 == string::npos))) &&
((count3 == 0) && (count4 == 0) && (count5 == 0) && (count6 == 0)
&& (count8 == 0) && (count9 == 0) ) )
{
back1 = system(cll1); //system call execution
if (!(back1 == 0))
{
b->Set(true, res);
return 0;
}
res = true;
b->Set(true, res);
return 0;
}
else {
b->Set(true, res);
return 0;
}
}
else
{
if ( (count1 == 1) && (count2 == 1) && (!((dot1 == string::npos)
|| (dot2 == string::npos))) &&
((count3 == 0) && (count4 == 0) && (count5 == 0) && (count6 == 0) ))
{
back1 = system(cll1);
if (!(back1 == 0))
{
b->Set(true, res);
return 0;
}
res = true;
b->Set(true, res);
return 0;
}
else {
b->Set(true, res);
return 0;
}
}
return 0; //never happens
}
struct embedTagsInfo {
map<string, int> toposvalue;
map<string, string> totypevalue;
int attrcount;
};
int embedTagsVM(Word* args, Word& result, int message, Word& local, Supplier s)
{
Word t, value;
Tuple* tup;
embedTagsInfo* localInfo = (embedTagsInfo*) qp->GetLocal2(s).addr;
switch (message)
{
case OPEN : {
ListExpr resultType = GetTupleResultType(s);
TupleType *tupleType = new TupleType(nl->Second(resultType));
local.addr = tupleType;
ListExpr attrsave = qp->GetType(qp->GetSon(s,0));
ListExpr attrsave2 = nl->Second(nl->Second(attrsave));
map<string, int> toposvalue2;
map<string, string> totypevalue2;
localInfo = new embedTagsInfo;
qp->GetLocal2(s).addr = localInfo;
int counter = 0;
while (!(nl->IsEmpty(attrsave2)))
{
ListExpr temp = nl->First(attrsave2);
ListExpr temp2 = nl->First(temp);
ListExpr temp3 = nl->Second(temp);
string attrname = nl->SymbolValue(temp2);
string typen = nl->SymbolValue(temp3);
//setting up the localInfo
localInfo->toposvalue.insert(pair<string, int> (attrname, counter));
localInfo->totypevalue.insert(pair<string, string> (attrname, typen));
attrsave2 = nl->Rest(attrsave2);
counter++;
}
localInfo->attrcount = counter;
qp->Open(args[0].addr);
return 0;
}
case REQUEST : {
int veclen;
bool wert = true;
size_t pos1 = 0;
string brack = "<<";
string brack2 = ">>";
vector<string> vstr;
map<string, int>::iterator iter=localInfo->toposvalue.begin();
int maxattrpos = 0;
qp->Request(args[0].addr,t);
//calculate max attribute position
maxattrpos = localInfo->attrcount - 1;
if (qp->Received(args[0].addr))
{
tup = (Tuple*)t.addr;
TupleType *tupleType = (TupleType*)local.addr;
Tuple *newTuple = new Tuple( tupleType );
// copy old attributes
for( int i = 0; i < tup->GetNoAttributes(); i++ ) {
newTuple->CopyAttribute( i, tup, i );
}
// get needed tuple values
int briefpos = ((CcInt*)args[4].addr)->GetIntval();
Attribute* brief = tup->GetAttribute(briefpos-1);
FText* briefval = static_cast<FText*>(brief);
string briefvalstr = briefval->GetValue();
//find the tags
while ((pos1 = briefvalstr.find(brack, pos1)) != std::string::npos)
{
size_t found = briefvalstr.find(brack,pos1);
size_t found2 = briefvalstr.find(brack2,pos1);
size_t lenght = found2-found-2;
string substr = briefvalstr.substr(found+2, lenght);
pos1 += substr.length();
vstr.push_back(substr);
}
//get the tag related attribute values
veclen = vstr.size();
Attribute* attrar[veclen];
string typear[veclen];
string strvalues[veclen];
for (int i=0; i<veclen; i++)
{
iter = localInfo->toposvalue.find(vstr[i]);
if (iter == localInfo->toposvalue.end())
{
wert = false;
FText* brief2 = new FText (true,
"Error: one tag is not related to an attribute");
newTuple->PutAttribute(maxattrpos+1, brief2);
CcBool* wert2 = new CcBool(true, wert);
newTuple->PutAttribute(maxattrpos+2, wert2);
tup->DeleteIfAllowed();
result = SetWord(newTuple);
return YIELD;
}
attrar[i] = tup->GetAttribute(localInfo->toposvalue.at(vstr[i]));
if (!(attrar[i]->IsDefined()))
{
wert = false;
FText* brief2 = new FText (true,
"ERROR: tag related attribute undef");
newTuple->PutAttribute(maxattrpos+1, brief2);
CcBool* wert2 = new CcBool(true, wert);
newTuple->PutAttribute(maxattrpos+2, wert2);
tup->DeleteIfAllowed();
result = SetWord(newTuple);
return YIELD;
}
typear[i] = localInfo->totypevalue.at(vstr[i]);
if ( !( (typear[i] == "string") || (typear[i] == "text")
|| (typear[i] == "real") || (typear[i] == "int")
|| (typear[i] == "date") ) )
{ wert = false;
FText* brief2 = new FText (true,
"ERROR: tag related attribute type is not supported");
newTuple->PutAttribute(maxattrpos+1, brief2);
CcBool* wert2 = new CcBool(true, wert);
newTuple->PutAttribute(maxattrpos+2, wert2);
tup->DeleteIfAllowed();
result = SetWord(newTuple);
return YIELD;
}
// end of error cases
//extract the attribute values
if (typear[i] == "string")
{
CcString* temp1 = static_cast<CcString*>(attrar[i]);
strvalues[i] = temp1->GetValue();
}
if (typear[i] == "text")
{
FText* temp3= static_cast<FText*>(attrar[i]);
strvalues[i] = temp3->GetValue();
}
if (typear[i] == "real")
{
CcReal* temp4 = static_cast<CcReal*>(attrar[i]);
double val = temp4-> GetRealval();
ostringstream Str;
Str << val;
string valstr(Str.str());
strvalues[i] = valstr;
}
if (typear[i] == "int")
{
CcInt* temp5= static_cast<CcInt*>(attrar[i]);
int val2 = temp5-> GetIntval();
ostringstream Str2;
Str2 << val2;
string valstr2(Str2.str());
strvalues[i] = valstr2;
}
if (typear[i] == "date")
{
string datevalue = attrar[i]->getCsvStr();
strvalues[i] = datevalue;
}
} //end of for
//replace tags with attribute values
for (int i= 0; i<veclen; i++)
{ string tagme = "<<" + vstr[i] + ">>";
size_t prosit = 0;
if (briefvalstr.find(tagme, prosit) != string::npos)
{
while ( (prosit = briefvalstr.find(tagme, prosit))
!= std::string::npos)
{
briefvalstr.replace(prosit, tagme.length(), strvalues[i]);
prosit += strvalues[i].length();
}
}
}
// setting up the new tuple
wert = true;
FText* brief2 = new FText (true, briefvalstr);
newTuple->PutAttribute(maxattrpos+1, brief2);
CcBool* wert2 = new CcBool(true, wert);
newTuple->PutAttribute(maxattrpos+2, wert2);
tup->DeleteIfAllowed();
result = SetWord(newTuple);
return YIELD;
}
else
return CANCEL; // no args left
}
case CLOSE : {
if(localInfo){
delete localInfo;
qp->GetLocal2(s).addr=0;
}
qp->Close(args[0].addr);
if (local.addr)
{
((TupleType*)local.addr)->DeleteIfAllowed();
local.setAddr(0);
}
return 0;
}
} //end switch
return 0;
}
/*
1.4 Specification for ~sendmail~
*/
const string sendmailSpec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) "
"( <text>text x text x text x text, text -> bool </text--->"
"<text>sendmail (subject, sender, receiver, message, carboncopy) </text--->"
"<text>Sends a mail to the address specified "
"with the third argument. The second argument "
"is the sender address. "
"The first argument is the subject of the mail "
"and the fourth is the message. "
" With the fifth argumemt you can put in a carbon copy address."
" Just type in the empty text ('') if you do not want a copy. "
" TRUE is returned if there are no email address syntax errors."
" FALSE is returned if the address is not syntactically correct"
" and UNDEFINED if any other error occurs.</text--->"
"<text> query sendmail('a subject', 'sender@universe2.com', "
"'receiver@universe1.com', 'message' 'someone@universe3.com) </text--->"
") )";
/*
2.4 Specification for ~embedTags~
*/
const string embedTagsSpec =
"( ( \"Signature\" \"Syntax\" \"Meaning\" "
"\"Example\" ) "
"( <text>((stream (tuple ((x1 T1) ... "
"(xn Tn)))) (ak1, ak2, ak3)) -> (stream (tuple"
" ((ai1 Ti1) ... (ain Tin) (ak2, Tk2) (ak3, Tk3))))</text--->"
"<text>_ embedTags [ list ]</text--->"
"<text>Produces a tuple for each "
"tuple of its input stream "
"with two additional appended attributes. "
"The tuple stream that is fed in must have "
"certain attributes including one "
"that is specified by ak1. This must be a "
"text value with some tags in << >> brackets. "
"For example, if these tags are <<Note>>, <<Kurs>>, <<Nachname<< and <<Dr>> "
"then Note, Kurs, Nachname, Dr must also be attributes in the "
"tuple stream that is fed in. In the result stream the tags are "
"replaced with the corresponding attribute values and the modified "
"text is a value of the attribute ak2. Furthermore a bool attribute "
"is appended which will have the value FALSE if something went wrong, "
"or TRUE if the text was modified correctly. </text--->"
"<text> query pruefung feed embedTags[Brief, Brief2, Erfolg] "
" consume </text--->"
") )";
Operator sendmail ( "sendmail",
sendmailSpec,
sendmailVM,
Operator::SimpleSelect,
sendmailtypemap );
Operator embedTags( "embedTags",
embedTagsSpec,
embedTagsVM,
Operator::SimpleSelect,
embedTagstypemap );
/*
1.6 Creating the Algebra
*/
class MailAlgebra : public Algebra
{
public:
MailAlgebra() : Algebra()
{
AddOperator( &sendmail);
AddOperator( &embedTags);
}
~MailAlgebra() {};
};
/*
1.7 Initialization
*/
extern "C"
Algebra*
InitializeMailAlgebra( NestedList* nlRef, QueryProcessor* qpRef )
{
nl = nlRef;
qp = qpRef;
return (new MailAlgebra());
}