void ListAliases::execute() { if ( !q ) { Utf8Codec c; UString pattern = c.toUnicode( next() ); end(); if ( !c.valid() ) error( "Argument encoding: " + c.error() ); database(); EString s( "select (localpart||'@'||domain)::text as address, m.name " "from aliases join addresses a on (address=a.id) " "join mailboxes m on (mailbox=m.id)" ); if ( !pattern.isEmpty() ) s.append( " where localpart||'@'||domain like $1 or " "m.name like $1" ); q = new Query( s, this ); if ( !pattern.isEmpty() ) q->bind( 1, sqlPattern( pattern ) ); q->execute(); } while ( q->hasResults() ) { Row * r = q->nextRow(); printf( "%s: %s\n", r->getEString( "address" ).cstr(), r->getUString( "name" ).utf8().cstr() ); } if ( !q->done() ) return; finish(); }
UString SmtpParser::subDomain() { EString e; char c = nextChar(); if ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || ( c >= '0' && c <= '9' ) || ( c >= 128 ) ) { do { e.append( c ); step(); c = nextChar(); } while ( ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || ( c >= '0' && c <= '9' ) || ( c == '-' || c >= 128 ) ) ); } if ( e.isEmpty() && c == '.' ) setError( "Consecutive dots aren't permitted" ); else if ( e.isEmpty() ) setError( "Domain cannot end with a dot" ); else if ( e[e.length()-1] == '-' ) setError( "subdomain cannot end with hyphen (" + e + ")" ); else if ( e.startsWith( "xn--" ) ) setError( "subdomain cannot be an a-label (" + e + ")" ); Utf8Codec u; UString r = u.toUnicode( e ); if ( !u.valid() ) setError( "Subdomain (" + e + ") is not valid UTF8: " + u.error() ); return r; }
bool PopCommand::user() { if ( !d->user ) { log( "USER Command" ); if ( !d->pop->accessPermitted() ) { d->pop->err( "Must enable TLS before login" ); return true; } d->user = new ::User; Utf8Codec c; d->user->setLogin( c.toUnicode( nextArg() ) ); d->pop->setUser( d->user, "POP3 login" ); if ( c.valid() ) { d->user->refresh( this ); } else { d->pop->err( "Argument encoding error: " + c.error() ); d->pop->badUser(); return true; } } if ( d->user->state() == User::Unverified ) return false; if ( d->user->state() == User::Nonexistent ) { d->pop->err( "No such user" ); d->pop->badUser(); } else { d->pop->ok( "Done" ); } return true; }
UString SmtpParser::atom() { char c = nextChar(); EString r; while ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || ( c >= '0' && c <= '9' ) || c == '!' || c == '#' || c == '$' || c == '%' || c == '&' || c == '\'' || c == '*' || c == '+' || c == '-' || c == '/' || c == '=' || c == '?' || c == '^' || c == '_' || c == '`' || c == '{' || c == '|' || c == '}' || c == '~' || c >= 128 ) { r.append( c ); step(); c = nextChar(); } if ( r.isEmpty() ) setError( "Expected atom, saw: " + following() ); Utf8Codec uc; UString u = uc.toUnicode( r ); if ( !uc.valid() ) setError( "Unicode error in atom (" + uc.error() + "): " + r ); return u; }
UString SmtpParser::quotedString() { require( "\"" ); EString r; while ( ok() && !atEnd() && nextChar() != '"' ) { if ( nextChar() == '\\' ) step(); r.append( nextChar() ); step(); } require( "\"" ); Utf8Codec c; UString u = c.toUnicode( r ); if ( !c.valid() ) setError( "Unicode error in string (" + c.error() + "): " + r ); return u; }
UString SieveParser::quotedString() { EString r; require( "\"" ); while ( ok() && !atEnd() && nextChar() != '"' ) { if ( present( "\r\n" ) ) { r.append( "\r\n" ); } else { if ( nextChar() == '\\' ) step(); r.append( nextChar() ); step(); } } require( "\"" ); Utf8Codec c; UString u = c.toUnicode( r ); if ( !c.valid() ) setError( "Encoding error: " + c.error() ); return u; }
UString SieveParser::multiLine() { EString r; require( "text:" ); while ( ok() && ( nextChar() == ' ' || nextChar() == '\t' ) ) step(); if ( !present( "\r\n" ) ) hashComment(); while ( ok() && !atEnd() && !present( ".\r\n" ) ) { if ( nextChar() == '.' ) step(); while ( ok() && !atEnd() && nextChar() != '\r' ) { r.append( nextChar() ); step(); } require( "\r\n" ); r.append( "\r\n" ); } Utf8Codec c; UString u = c.toUnicode( r ); if ( !c.valid() ) setError( "Encoding error: " + c.error() ); return u; }
void CreateAlias::execute() { if ( !d->address ) { Utf8Codec c; parseOptions(); d->address = nextAsAddress(); EString * first = args()->firstElement(); if ( first && !first->startsWith( "/" ) && first->contains( "@" ) ) d->destination = nextAsAddress(); else d->mailboxName = c.toUnicode( next() ); end(); if ( !c.valid() ) error( "Argument encoding: " + c.error() ); database( true ); if ( !d->mailboxName.isEmpty() ) Mailbox::setup( this ); } if ( !choresDone() ) return; if ( !d->t ) { if ( !d->mailboxName.isEmpty() ) { d->mailbox = Mailbox::obtain( d->mailboxName, false ); if ( !d->mailbox || d->mailbox->deleted() ) error( "No mailbox named " + d->mailboxName.utf8() ); } d->t = new Transaction( this ); List< Address > l; l.append( d->address ); if ( d->destination ) l.append( d->destination ); AddressCreator * ac = new AddressCreator( &l, d->t ); ac->execute(); } if ( !d->address->id() || ( d->destination && !d->destination->id() ) ) return; if ( !d->q ) { if ( d->destination ) { d->q = new Query( "insert into aliases (address, mailbox) " "select $1, mailbox from aliases al " "join addresses a on (al.address=a.id) " "where a.localpart=$2" " and a.domain=$3 " "limit 1", this ); d->q->bind( 1, d->address->id() ); d->q->bind( 2, d->destination->localpart() ); d->q->bind( 3, d->destination->domain() ); } else { d->q = new Query( "insert into aliases (address, mailbox) " "values ($1, $2)", this ); d->q->bind( 1, d->address->id() ); d->q->bind( 2, d->mailbox->id() ); } d->t->enqueue( d->q ); d->t->execute(); } if ( !d->q->done() ) return; if ( d->q->failed() ) error( "Couldn't create alias: " + d->q->error() ); if ( d->q->rows() < 1 ) error( "Could not locate destination for alias" ); else if ( d->q->rows() > 1 ) error( "Internal error: Inserted " + fn( d->q->rows() ) + " instead of 1. Not committing." ); d->t->commit(); finish(); }
void ImapUrl::parse( const EString & s ) { d->orig = s; ImapUrlParser * p = new ImapUrlParser( s ); // imapurl = "imap://" iserver "/" icommand if ( !d->imap ) { if ( !p->present( "imap://" ) ) return; // iserver = [ iuserauth "@" ] hostport // iuserauth = enc_user [iauth] / [enc_user] iauth if ( p->hasIuserauth() ) { d->user = new User; Utf8Codec c; d->user->setLogin( c.toUnicode( p->xchars() ) ); if ( !c.valid() ) return; if ( p->present( ";AUTH=" ) ) d->auth = p->xchars(); else if ( d->user->login().isEmpty() ) return; if ( !p->present( "@" ) ) return; } if ( !p->hostport( d->host, &d->port ) ) return; } // icommand = enc_mailbox [uidvalidity] iuid [isection] if ( !( d->imap && d->imap->session() ) || !p->hasUid() ) { if ( !p->present( "/" ) ) return; Utf8Codec c; d->mailbox = c.toUnicode( p->xchars( true ) ); if ( d->mailbox.isEmpty() ) return; if( !c.valid() ) return; if ( p->present( ";uidvalidity=" ) ) { d->uidvalidity = p->nzNumber(); if ( !p->ok() ) return; } } p->require( "/;uid=" ); d->uid = p->number(); if ( p->present( "/;section=" ) ) d->section = p->xchars( true ); // RFC 4467 additions: // [ ";EXPIRE=" date-time ] ";URLAUTH=" access ":" mechanism ":" urlauth // (These clauses apply only to absolute URLs.) if ( !d->imap ) { if ( p->nextChar() == ';' ) { if ( p->present( ";expire=" ) ) d->expires = p->isoTimestamp(); p->require( ";urlauth=" ); if ( p->present( "submit+" ) ) d->access = "submit+" + p->xchars(); else if ( p->present( "user+" ) ) d->access = "user+" + p->xchars(); else if ( p->present( "authuser" ) ) d->access = "authuser"; else if ( p->present( "anonymous" ) ) d->access = "anonymous"; else return; d->rumpEnd = p->pos(); if ( p->present( ":" ) ) { p->require( "internal" ); p->require( ":" ); d->urlauth = p->urlauth(); d->mechanism = "internal"; } else { d->isRump = true; } } } p->end(); if ( !p->ok() ) return; d->valid = true; }
void CreateView::execute() { if ( d->name.isEmpty() ) { parseOptions(); Utf8Codec c; d->name = c.toUnicode( next() ); d->source = c.toUnicode( next() ); UString owner( c.toUnicode( next() ) ); d->selector = parseSelector( args() ); if ( !c.valid() ) error( "Argument encoding: " + c.error() ); if ( d->name.isEmpty() ) error( "No name supplied for the view." ); if ( d->source.isEmpty() ) error( "No source mailbox name supplied." ); if ( !d->selector ) error( "Invalid search expression supplied." ); database( true ); Mailbox::setup( this ); if ( !owner.isEmpty() ) { d->user = new User; d->user->setLogin( owner ); d->user->refresh( this ); } } if ( !choresDone() ) return; if ( !d->t ) { if ( d->user ) { if ( d->user->state() == User::Unverified ) return; if ( d->user->state() == User::Nonexistent ) error( "No user named " + d->user->login().utf8() ); if ( !d->name.startsWith( "/" ) ) d->name = d->user->home()->name() + "/" + d->name; if ( !d->source.startsWith( "/" ) ) d->source = d->user->home()->name() + "/" + d->source; } d->ms = Mailbox::obtain( d->source ); if ( !d->ms || d->ms->deleted() ) error( "Can't create view on " + d->source.utf8() ); d->t = new Transaction( this ); d->mv = Mailbox::obtain( d->name ); Query * q = d->mv->create( d->t, d->user ); if ( !q ) error( "Couldn't create view named " + d->name.utf8() ); q = new Query( "insert into views " "(view, selector, source, nextmodseq) values " "((select id from mailboxes where name=$1)," "$2, " "((select id from mailboxes where name=$3), " "1::bigint)", this ); q->bind( 1, d->name ); q->bind( 2, d->selector->string() ); q->bind( 3, d->ms->name() ); d->t->enqueue( q ); d->t->commit(); } if ( !d->t->done() ) return; if ( d->t->failed() ) error( "Couldn't create view" ); finish(); }
int main( int argc, char *argv[] ) { Scope global; EString sender; UString mailbox; EString recipient; EString filename; int verbose = 0; bool error = false; int n = 1; while ( n < argc ) { if ( argv[n][0] == '-' ) { switch ( argv[n][1] ) { case 'f': if ( argc - n > 1 ) sender = argv[++n]; break; case 't': if ( argc - n > 1 ) { Utf8Codec c; mailbox = c.toUnicode( argv[++n] ); if ( !c.valid() ) error = true; } break; case 'v': { int i = 1; while ( argv[n][i] == 'v' ) { verbose++; i++; } if ( argv[n][i] != '\0' ) error = true; } break; default: error = true; break; } } else if ( recipient.isEmpty() ) { recipient = argv[n]; } else if ( filename.isEmpty() ) { filename = argv[n]; } else { error = true; } n++; } if ( error || recipient.isEmpty() ) { fprintf( stderr, "Syntax: deliver [-v] [-f sender] recipient [filename]\n" ); exit( -1 ); } EString contents; if ( filename.isEmpty() ) { char s[128]; while ( fgets( s, 128, stdin ) != 0 ) contents.append( s ); } else { File message( filename ); if ( !message.valid() ) { fprintf( stderr, "Unable to open message file %s\n", filename.cstr() ); exit( -1 ); } contents = message.contents(); } Configuration::setup( "archiveopteryx.conf" ); Injectee * message = new Injectee; message->parse( contents ); if ( !message->error().isEmpty() ) { fprintf( stderr, "Message parsing failed: %s", message->error().cstr( ) ); exit( EX_DATAERR ); } if ( verbose > 0 ) fprintf( stderr, "Sending to <%s>\n", recipient.cstr() ); EventLoop::setup(); Database::setup( 1 ); Log * l = new Log; Allocator::addEternal( l, "delivery log" ); global.setLog( l ); Allocator::addEternal( new StderrLogger( "deliver", verbose ), "log object" ); Configuration::report(); Mailbox::setup(); Deliverator * d = new Deliverator( message, mailbox, recipient ); EventLoop::global()->start(); if ( !d->i || d->i->failed() ) return EX_UNAVAILABLE; if ( verbose ) fprintf( stderr, "deliver: Stored in %s as UID %d\n", d->mb->name().utf8().cstr(), d->m->uid( d->mb ) ); return 0; }
int main( int ac, char ** av ) { Scope global; bool bad = false; if ( ac < 1 ) bad = true; Configuration::setup( "archiveopteryx.conf" ); EventLoop::setup(); Log * l = new Log; Allocator::addEternal( l, "aoxexport log" ); global.setLog( l ); LogClient::setup( "aoxexport" ); Configuration::report(); int i = 1; while( i < ac && *av[i] == '-' ) { uint j = 1; while ( av[i][j] ) { switch( av[i][j] ) { case 'v': verbosity++; break; case 'q': if ( verbosity ) verbosity--; break; default: bad = true; break; } j++; } i++; } Utf8Codec c; UString source; if ( i >= ac ) bad = true; else if ( av[i][0] == '/' ) source = c.toUnicode( av[i++] ); Selector * which; if ( i < ac ) { EStringList args; while ( i < ac ) args.append( new EString( av[i++] ) ); which = parseSelector( &args ); } else { which = new Selector( Selector::NoField, Selector::All, 0 ); } if ( bad ) { fprintf( stderr, "Usage: %s [-vq] [mailbox] [search]" "See aoxexport(8) or " "http://aox.org/aoxexport/ for details.\n", av[0] ); exit( -1 ); } if ( !c.valid() ) { fprintf( stderr, "%s: Mailbox name could not be converted from UTF-8: %s\n", av[0], c.error().cstr() ); exit( -1 ); } Entropy::setup(); Database::setup(); Exporter * e = new Exporter( source, which ); Mailbox::setup( e ); EventLoop::global()->start(); return 0; }