예제 #1
0
EString MimeField::rfc822() const
{
    EString s = baseValue();
    uint lineLength = name().length() + 2 + s.length();

    EStringList words;
    List< MimeFieldData::Parameter >::Iterator it( d->parameters );
    while ( it ) {
        EString s = it->value;
        if ( !s.boring( EString::MIME ) )
            s = s.quoted();
        words.append( it->name + "=" + s );
        ++it;
    }

    while ( !words.isEmpty() ) {
        EStringList::Iterator i( words );
        while ( i && lineLength + 2 + i->length() > 78 )
            ++i;
        if ( i ) {
            s.append( "; " );
            lineLength += 2;
        }
        else {
            i = words;
            s.append( ";\r\n " );
            lineLength = 1;
        }
        s.append( *i ); // XXX need more elaboration for 2231
        lineLength += i->length();
        words.take( i );
    }
    return s;
}
예제 #2
0
파일: multipart.cpp 프로젝트: aox/aox
static void headerSummary( Header * h, int n )
{
    EStringList l;

    ContentType * ct = h->contentType();
    if ( ct )
        l.append( ct->type() + "/" + ct->subtype() );

    ContentTransferEncoding * cte = h->contentTransferEncoding();
    if ( cte ) {
        EString s;
        switch ( cte->encoding() ) {
        case EString::QP:
            s = "quoted-printable";
            break;
        case EString::Base64:
            s = "base64";
            break;
        case EString::Uuencode:
            s = "x-uuencode";
            break;
        case EString::Binary:
            s = "7bit";
            break;
        }
        l.append( s );
    }

    HeaderField * cd = h->field( HeaderField::ContentDescription );
    if ( cd )
        l.append( cd->rfc822( false ) );

    if ( !l.isEmpty() ) {
        spaces( n );
        fprintf( stderr, "%s\n", l.join( ";" ).cstr() );
    }
}
예제 #3
0
파일: recorder.cpp 프로젝트: aox/aox
int main( int argc, char ** argv )
{
    Scope global;
    EventLoop::setup();

    const char * error = 0;
    bool ok = true;
    if ( argc != 5 ) {
        error = "Wrong number of arguments";
        ok = false;
    }

    uint port = 0;
    if ( ok ) {
        port = EString( argv[1] ).number( &ok );
        if ( !ok )
            error = "Could not parse own port number";
    }
    if ( ok ) {
        Listener<RecorderServer> * l4
            = new Listener<RecorderServer>( Endpoint( "0.0.0.0", port ),
                                            "recording relay/4" );
        Allocator::addEternal( l4, "recording listener" );
        Listener<RecorderServer> * l6
            = new Listener<RecorderServer>( Endpoint( "::", port ),
                                            "recording relay/6" );
        Allocator::addEternal( l6, "recording listener" );

        if ( l4->state() != Connection::Listening &&
             l6->state() != Connection::Listening )
            error = "Could not listen for connections";
    }

    if ( ok ) {
        port = EString( argv[3] ).number( &ok );
        if ( !ok )
            error = "Could not parse server's port number";
    }

    if ( ok ) {
        EStringList l = Resolver::resolve( argv[2] );
        if ( l.isEmpty() ) {
            ok = false;
            error = (EString("Cannot resolve ") + argv[2] +
                     ": " + Resolver::errors().join( ", " ) ).cstr();
        }
        else {
            ep = new Endpoint( *l.first(), port );
            Allocator::addEternal( ep, "target server endpoint" );
        }
        if ( ep && !ep->valid() ) {
            ok = false;
            error = "Invalid server address";
        }
    }

    if ( !ok ) {
        fprintf( stderr,
                 "Error: %s\n"
                 "Usage: recorder port address port filebase\n"
                 "       First port: The recorder's own port.\n"
                 "       Address: The IP address of the server to forward to.\n"
                 "       Second port: The server port to forward to.\n"
                 "       Filebase: The filename base (.<blah> is added).\n",
                 error );
        exit( 1 );
    }

    ::base = new EString( argv[4] );
    Allocator::addEternal( ::base, "base of recorded file names" );

    global.setLog( new Log );
    EventLoop::global()->start();
}
예제 #4
0
파일: pop.cpp 프로젝트: netconstructor/aox
void POP::parse()
{
    Buffer *b = readBuffer();

    while ( b->size() > 0 ) {
        if ( !d->reader ) {
            if ( d->reserved )
                break;

            EString * s = b->removeLine( 255 );

            if ( !s && b->size() < 255 )
                return;

            if ( !s ) {
                log( "Connection closed due to overlong line (" +
                     fn( b->size() ) + " bytes)", Log::Error );
                err( "Line too long. Closing connection." );
                Connection::setState( Closing );
                return;
            }

            bool unknown = false;

            EStringList * args = EStringList::split( ' ', *s );
            EString cmd = args->take( args->first() )->lower();

            if ( d->sawUser && !( cmd == "quit" || cmd == "pass" ) ) {
                d->sawUser = false;
                unknown = true;
            }
            else if ( cmd == "quit" && args->isEmpty() ) {
                newCommand( d->commands, this, PopCommand::Quit );
            }
            else if ( cmd == "capa" && args->isEmpty() ) {
                newCommand( d->commands, this, PopCommand::Capa );
            }
            else if ( d->state == Authorization ) {
                if ( cmd == "stls" ) {
                    if ( hasTls() )
                        err( "Nested STLS" );
                    else
                        newCommand( d->commands, this, PopCommand::Stls );
                }
                else if ( cmd == "auth" ) {
                    newCommand( d->commands, this, PopCommand::Auth, args );
                }
                else if ( cmd == "user" && args->count() == 1 ) {
                    d->sawUser = true;
                    newCommand( d->commands, this, PopCommand::User, args );
                }
                else if ( d->sawUser && cmd == "pass" && args->count() >= 1 ) {
                    d->sawUser = false;
                    newCommand( d->commands, this, PopCommand::Pass, args );
                }
                else if ( cmd == "apop" && args->count() == 2 ) {
                    newCommand( d->commands, this, PopCommand::Apop, args );
                }
                else {
                    unknown = true;
                }
            }
            else if ( d->state == Transaction ) {
                if ( cmd == "stat" && args->isEmpty() ) {
                    newCommand( d->commands, this, PopCommand::Stat );
                }
                else if ( cmd == "list" && args->count() < 2 ) {
                    newCommand( d->commands, this, PopCommand::List, args );
                }
                else if ( cmd == "top" && args->count() == 2 ) {
                    newCommand( d->commands, this, PopCommand::Top, args );
                }
                else if ( cmd == "retr" && args->count() == 1 ) {
                    newCommand( d->commands, this, PopCommand::Retr, args );
                }
                else if ( cmd == "dele" && args->count() == 1 ) {
                    newCommand( d->commands, this, PopCommand::Dele, args );
                }
                else if ( cmd == "noop" && args->isEmpty() ) {
                    newCommand( d->commands, this, PopCommand::Noop );
                }
                else if ( cmd == "rset" && args->isEmpty() ) {
                    newCommand( d->commands, this, PopCommand::Rset );
                }
                else if ( cmd == "uidl" && args->count() < 2 ) {
                    newCommand( d->commands, this, PopCommand::Uidl, args );
                }
                else {
                    unknown = true;
                }
            }
            else {
                unknown = true;
            }

            if ( unknown ) {
                err( "Bad command" );
                recordSyntaxError();
            }
        }
        else {
            d->reader->read();
        }

        runCommands();
    }
}
예제 #5
0
파일: sievescript.cpp 프로젝트: aox/aox
void SieveScript::parse( const EString & script )
{
    d->source = script;
    SieveParser p( script );
    d->script = p.commands();

    // if we're not yet at the end, treat whatever follows as another
    // command, which will have a nice big error message.
    p.whitespace();
    if ( !p.atEnd() ) {
        SieveCommand * sc = p.command();
        sc->setError( "Junk at end of script" );
        d->script->append( sc );
    }

    // require is only permitted at the start
    List<SieveCommand>::Iterator s( d->script );
    while ( s && s->identifier() == "require" ) {
        s->setRequirePermitted( true );
        ++s;
    }

    // do the semantic bits of parsing
    s = d->script->first();
    EString prev;
    while ( s ) {
        s->setParent( this );
        s->parse( prev );
        prev = s->identifier();
        ++s;
    }

    // check that require lists the right extensions
    EStringList * extensions = p.extensionsNeeded();
    EStringList declared;
    s = d->script->first();
    while ( s && s->identifier() == "require" ) {
        if ( s->error().isEmpty() ) {
            UStringList * r = 0;
            if ( s->arguments() &&
                 s->arguments()->arguments() &&
                 s->arguments()->arguments()->first() )
                r = s->arguments()->arguments()->first()->stringList();
            UStringList::Iterator i( r );
            while ( i ) {
                if ( i->isAscii() )
                    declared.append( i->ascii() );
                ++i;
            }
        }
        ++s;
    }
    declared.append( "comparator-i;octet" );
    declared.append( "comparator-i;ascii-casemap" );
    declared.append( "fileinto" );
    declared.append( "reject" );
    EStringList::Iterator i( extensions );
    EStringList undeclared;
    while ( i ) {
        if ( !declared.contains( *i ) )
            undeclared.append( i->quoted() );
        ++i;
    }
    if ( !undeclared.isEmpty() ) {
        SieveCommand * f = d->script->first();
        if ( f->identifier() == "require" )
            f->setError( "Extensions used but not declared: " +
                         undeclared.join( ", " ) );
        else
            f->setError( "Missing require: require [ " +
                         undeclared.join( ", " ) + " ];" );
    }

    // and find all the errors
    d->errors = p.bad( this );
}
예제 #6
0
void SieveCommand::parse( const EString & previous )
{
    if ( identifier().isEmpty() )
        setError( "Command name is empty" );

    bool test = false;
    bool blk = false;

    EString i = identifier();
    if ( i == "if" || i == "elsif" ) {
        test = true;
        blk = true;
        if ( i == "elsif" && previous != "if" && previous != "elsif" )
            setError( "elsif is only permitted after if/elsif" );
    }
    else if ( i == "else" ) {
        blk = true;
        if ( previous != "if" && previous != "elsif" )
            setError( "else is only permitted after if/elsif" );
    }
    else if ( i == "require" ) {
        arguments()->numberRemainingArguments();
        UStringList::Iterator i( arguments()->takeStringList( 1 ) );
        EStringList a;
        EStringList e;
        while ( i ) {
            if ( supportedExtensions()->contains( i->ascii() ) )
                a.append( i->ascii().quoted() );
            else
                e.append( i->ascii().quoted() );
            ++i;
        }
        if ( !e.isEmpty() )
            setError( "Each string must be a supported "
                      "sieve extension. "
                      "These are not: " + e.join( ", " ) );
        if ( !d->require )
            setError( "require is only permitted as the first command." );
        else if ( parent() )
            parent()->addExtensions( &a );
    }
    else if ( i == "stop" ) {
        // nothing needed
    }
    else if ( i == "reject" ) {
        require( "reject" );
        if ( arguments()->arguments()->isEmpty() ) {
            // we accept reject without reason
        }
        else {
            // if there is an argument, it must be a string
            arguments()->numberRemainingArguments();
            (void)arguments()->takeString( 1 );
        }
    }
    else if ( i == "ereject" ) {
        require( "reject" );
        arguments()->numberRemainingArguments();
        (void)arguments()->takeString( 1 );
    }
    else if ( i == "fileinto" ) {
        require( "fileinto" );
        if ( arguments()->findTag( ":copy" ) )
            require( "copy" );
        if ( arguments()->findTag( ":flags" ) ) {
            require( "imap4flags" );
            (void)arguments()->takeTaggedStringList( ":copy" );
        }
        arguments()->numberRemainingArguments();
        UString mailbox = arguments()->takeString( 1 );
        UString p;
        p.append( "/" );
        p.append( mailbox );

        if ( !Mailbox::validName( mailbox ) && !Mailbox::validName( p ) ) {
            setError( "Expected mailbox name, but got: " + mailbox.utf8() );
        }
        else if ( mailbox.startsWith( "INBOX." ) ) {
            // a sieve script which wants to reference a
            // mailbox called INBOX.X must use lower case
            // (inbox.x).
            UString aox =
                UStringList::split( '.', mailbox.mid( 6 ) )->join( "/" );
            setError( mailbox.utf8().quoted() +
                      " is Cyrus syntax. Archiveopteryx uses " +
                      aox.utf8().quoted() );
        }
    }
    else if ( i == "redirect" ) {
        (void)arguments()->findTag( ":copy" );
        arguments()->numberRemainingArguments();
        EString s = arguments()->takeString( 1 ).utf8();
        AddressParser ap( s );
        ap.assertSingleAddress();
        if ( !ap.error().isEmpty() )
            setError( "Expected one normal address (local@domain), but got: "
                      + s );
    }
    else if ( i == "keep" ) {
        // nothing needed
    }
    else if ( i == "discard" ) {
        // nothing needed
    }
    else if ( i == "vacation" ) {
        // vacation [":days" number] [":subject" string]
        //          [":from" string] [":addresses" string-list]
        //          [":mime"] [":handle" string] <reason: string>

        require( "vacation" );

        // :days
        uint days = 7;
        if ( arguments()->findTag( ":days" ) )
            days = arguments()->takeTaggedNumber( ":days" );
        if ( days < 1 || days > 365 )
            arguments()->tagError( ":days", "Number must be 1..365" );

        // :subject
        (void)arguments()->takeTaggedString( ":subject" );
        // anything is acceptable, right?

        // :from
        if ( arguments()->findTag( ":from" ) ) {
            parseAsAddress( arguments()->takeTaggedString( ":from" ),
                            ":from" );
            // XXX we don't enforce its being a local address.
        }

        // :addresses
        if ( arguments()->findTag( ":addresses" ) ) {
            UStringList * addresses
                = arguments()->takeTaggedStringList( ":addresses" );
            UStringList::Iterator i( addresses );
            while ( i ) {
                parseAsAddress( *i, ":addresses" );
                ++i;
            }
        }

        // :mime
        bool mime = false;
        if ( arguments()->findTag( ":mime" ) )
            mime = true;

        // :handle
        (void)arguments()->takeTaggedString( ":handle" );

        // reason
        arguments()->numberRemainingArguments();
        UString reason = arguments()->takeString( 1 );
        if ( mime ) {
            if ( !reason.isAscii() )
                setError( ":mime bodies must be all-ASCII, "
                          "8-bit text is not permitted" ); // so says the RFC
            EString x = reason.utf8();
            uint i = 0;
            Header * h = Message::parseHeader( i, x.length(),
                                               x, Header::Mime );
            Bodypart * bp = Bodypart::parseBodypart( i, x.length(),
                                                     x, h, 0 );
            if ( !h->error().isEmpty() )
                setError( "While parsing MIME header: " + h->error() );
            else if ( !bp->error().isEmpty() )
                setError( "While parsing MIME bodypart: " + bp->error() );

            List<HeaderField>::Iterator f( h->fields() );
            while ( f ) {
                if ( !f->name().startsWith( "Content-" ) )
                    setError( "Header field not permitted: " + f->name() );
                ++f;
            }

            if ( bp->children()->isEmpty() && bp->text().isEmpty() )
                setError( "Vacation reply does not contain any text" );
        }
        else {
            if ( reason.isEmpty() )
                setError( "Empty vacation text does not make sense" );
        }
    }
    else if ( i == "setflag" ||
              i == "addflags" ||
              i == "removeflag" ) {
        arguments()->numberRemainingArguments();
        (void)arguments()->takeStringList( 1 );
    }
    else if ( i == "notify" ) {
        require( "enotify" );
        UString from;
        if ( arguments()->findTag( ":from" ))
            from = arguments()->takeTaggedString( ":from" );

        UString importance;
        importance.append( "2" );
        if ( arguments()->findTag( ":importance" ) )
            importance = arguments()->takeTaggedString( ":from" );
        uint c = importance[0];
        if ( c < '1' || c > '3' )
            arguments()->tagError( ":importance",
                                   "Importance must be 1, 2 or 3" );

        UStringList * options;
        if ( arguments()->findTag( ":options" ) )
            options = arguments()->takeTaggedStringList( ":options" );

        UString message;
        if ( arguments()->findTag( ":message" ) )
            message = arguments()->takeTaggedString( ":message" );

        arguments()->numberRemainingArguments();
        UString method = arguments()->takeString( 1 );

        SieveNotifyMethod * m
            = new SieveNotifyMethod( method,
                                     arguments()->takeArgument( 1 ),
                                     this );

        if ( m->valid() ) {
            if ( arguments()->findTag( ":from" ) )
                m->setFrom( from, arguments()->findTag( ":from" ) );
            if ( arguments()->findTag( ":message" ) )
                m->setMessage( message, arguments()->findTag( ":message" ) );
        }
    }
    else {
        setError( "Command unknown: " + identifier() );
    }

    arguments()->flagUnparsedAsBad();

    if ( test ) {
        // we must have a test
        if ( !arguments() || arguments()->tests()->count() != 1 )
            setError( "Command " + identifier() + " requires one test" );
        if ( arguments() ) {
            List<SieveTest>::Iterator i( arguments()->tests() );
            while ( i ) {
                i->parse();
                if ( blk && block() ) {
                    if ( i->ihaveFailed() )
                        block()->setIhaveFailed();
                    else
                        block()->addExtensions( i->addedExtensions() );
                }
                ++i;
            }
        }
    }
    else {
        // we cannot have a test
        if ( arguments() && arguments()->tests()->isEmpty() ) {
            List<SieveTest>::Iterator i( arguments()->tests() );
            while ( i ) {
                i->setError( "Command " + identifier() +
                             " does not use tests" );
                ++i;
            }
        }
    }

    if ( blk ) {
        // we must have a subsidiary block
        if ( !block() ) {
            setError( "Command " + identifier() +
                      " requires a subsidiary {..} block" );
        }
        else {
            EString prev;
            List<SieveCommand>::Iterator i( block()->commands() );
            while ( i ) {
                i->parse( prev );
                prev = i->identifier();
                ++i;
            }
        }
    }
    else {
        // we cannot have a subsidiary block
        if ( block() )
            block()->setError( "Command " + identifier() +
                               " does not use a subsidiary command block" );
        // in this case we don't even bother syntax-checking the test
        // or block
    }
}