Esempio n. 1
0
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 );
}
Esempio n. 2
0
bool ManageSieveCommand::putScript()
{
    if ( !d->t ) {
        d->name = string();
        whitespace();
        d->script = string();
        end();
        if ( d->script.isEmpty() ) {
            no( "Script cannot be empty" );
            return true;
        }
        SieveScript script;
        script.parse( d->script.crlf() );
        EString e = script.parseErrors();
        if ( !e.isEmpty() ) {
            no( e );
            return true;
        }
        if ( d->name.isEmpty() ) {
            log( "Syntax checking only" );
            // Our very own syntax-checking hack.
            return true;
        }

        // look for fileinto calls. if any refer to nonexistent
        // mailboxes in the user's namespace, create those. if any
        // refer to mailboxes not owned by the user, deny the command.
        List<SieveCommand> stack;
        stack.append( script.topLevelCommands() );
        while ( !stack.isEmpty() ) {
            SieveCommand * c = stack.shift();
            if ( c->block() )
                stack.append( c->block()->commands() );
            if ( c->error().isEmpty() && c->identifier() == "fileinto" ) {
                SieveArgumentList * l = c->arguments();
                List<SieveArgument>::Iterator a( l->arguments() );
                while ( a ) {
                    UString n = *a->stringList()->first();
                    Mailbox * home = d->sieve->user()->home();
                    Mailbox * m = 0;
                    if ( n.startsWith( "/" ) )
                        m = Mailbox::obtain( n, true );
                    else
                        m = Mailbox::obtain( home->name() + "/" + n, true );
                    Mailbox * p = m;
                    while ( p && p != home )
                        p = p->parent();
                    if ( !m->deleted() ) {
                        // no action needed
                    }
                    else if ( p == home ) {
                        log( "Creating mailbox " + m->name().ascii() +
                             " (used in fileinto and did not exist)" );
                        d->create.insert( m->name().utf8(), m );
                    }
                    else {
                        no( "Script refers to mailbox " +
                            m->name().ascii().quoted() +
                            ", which does not exist and is outside your"
                            " home directory (" +
                            home->name().ascii().quoted() + ")" );
                        return true;
                    }
                    ++a;
                }
            }
        }

        // at this point, nothing can prevent us from completing.

        d->t = new Transaction( this );

        d->query = new Query( "select * from scripts "
                              "where name=$1 and owner=$2 "
                              "for update", this );
        d->query->bind( 1, d->name );
        d->query->bind( 2, d->sieve->user()->id() );
        d->t->enqueue( d->query );
        d->t->execute();

        Dict<Mailbox>::Iterator i( d->create );
        while ( i ) {
            (void)i->create( d->t, d->sieve->user() );
            ++i;
        }
        if ( !d->create.isEmpty() )
            Mailbox::refreshMailboxes( d->t );
    }

    if ( !d->query->done() )
        return false;

    if ( d->step == 0 ) {
        if ( d->query->nextRow() ) {
            d->query = new Query( "update scripts set script=$3 where "
                                  "owner=$1 and name=$2", 0 );
            log( "Updating script: " + d->name );
        }
        else {
            d->query = new Query( "insert into scripts "
                                  "(owner,name,script,active) "
                                  "values($1,$2,$3,false)", 0 );
            log( "Storing new script: " + d->name );
        }
        d->query->bind( 1, d->sieve->user()->id() );
        d->query->bind( 2, d->name );
        d->query->bind( 3, d->script );
        d->t->enqueue( d->query );

        d->step = 1;
        d->t->commit();
        return false;
    }

    if ( !d->t->done() )
        return false;

    Dict<Mailbox>::Iterator i( d->create );
    while ( i ) {
        d->ok.append( "Created mailbox " + i->name().utf8().quoted() + "." );
        ++i;
        if ( i )
            d->ok.append( "\r\n" );
    }

    return true;
}