Beispiel #1
0
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();
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
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;
}
Beispiel #8
0
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();
}
Beispiel #9
0
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;
}
Beispiel #10
0
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();
}
Beispiel #11
0
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;
}
Beispiel #12
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;
}