コード例 #1
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;
}