void IMAP::addCommand() { // I love this feature if ( d->str == "quit" ) d->str = "arnt logout"; ImapParser * p = new ImapParser( d->str ); EString tag = p->tag(); if ( !p->ok() ) { enqueue( "* BAD " + p->error() + "\r\n" ); recordSyntaxError(); log( p->error(), Log::Info ); return; } p->require( " " ); EString name = p->command(); if ( !p->ok() ) { enqueue( "* BAD " + p->error() + "\r\n" ); recordSyntaxError(); log( p->error(), Log::Error ); return; } if ( EventLoop::global()->inShutdown() && name != "logout" ) { uint n = 0; List< Command >::Iterator i( d->commands ); while ( i ) { if ( i->state() == Command::Executing ) n++; ++i; } if ( !n ) { enqueue( "* BYE Server or process shutdown\r\n" ); Connection::setState( Closing ); } enqueue( tag + " NO May not be started during server shutdown\r\n" ); return; } Command * cmd = Command::create( this, tag, name, p ); if ( !cmd ) { if ( Command::create( this, tag, tag, p ) ) enqueue( "* OK Hint: An IMAP command is prefixed by a tag. " "The command is the\r\n" "* OK second word on the line, after the tag. In " "your command, " + name.quoted() + "\r\n" "* OK is the command and " + tag.quoted() + " is the tag.\r\n" ); recordSyntaxError(); enqueue( tag + " BAD No such command: " + name + "\r\n" ); log( "Unknown command. Line: " + p->firstLine().quoted(), Log::Error ); return; } d->commands.append( cmd ); d->nextOkTime = time( 0 ) + 117; Scope x( cmd->log() ); if ( name.lower() != "login" && name.lower() != "authenticate" ) ::log( "First line: " + p->firstLine(), Log::Debug ); }
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(); } }