static void rwrite(Fcall *f) { Fid *fidp; int n; char *err, *argv[10]; fidp = newfid(f->fid); if(fidp->node->d.mode & DMDIR) { reply(f, "directories are not writable"); return; } if(fidp->open == 0) { reply(f, "file not open"); return; } if (!permitted(fidp, fidp->node, AWRITE)) { reply(f, "permission denied"); return; } f->data[f->count] = 0; /* the extra byte in rbuf leaves room */ n = tokenize(f->data, argv, 10); err = 0; switch(findkey(argv[0], cmds)) { case RELOAD: getconf(); reload(); break; case RDEBUG: if(n > 1) { debugfd = create(argv[1], OWRITE, 0666); if(debugfd < 0) err = "create failed"; } else debugfd = 2; break; case RNODEBUG: if(debugfd >= 0) close(debugfd); debugfd = -1; break; default: err = "unknown command"; break; } reply(f, err); }
/* add_host -- add the given host to the list of permitted hosts, provided it isn't already there. */ static void add_host (unsigned long host_addr) { int key; struct entry *new_entry; if (!permitted(host_addr, -1)) { if ((new_entry = (struct entry *) malloc(sizeof(struct entry))) == NULL) { fprintf(stderr,"%s: unable to malloc space for permitted host entry\n", progname); exit(1); } /* if */ new_entry->host_addr = host_addr; key = HASH(host_addr) % TABLE_SIZE; new_entry->next = permitted_hosts[key]; permitted_hosts[key] = new_entry; } /* if */ } /* add_host */
void Delete::execute() { if ( state() != Executing || !ok() ) return; if ( d->first ) { d->first = false; // We should really require DeleteMessages and Expunge only if // we know the mailbox isn't empty; but we'll know that inside // the transaction, and permitted() won't let us clean that up // if we don't have permission. So it'll have to wait until we // query permissions ourselves. requireRight( d->m, Permissions::DeleteMailbox ); requireRight( d->m, Permissions::DeleteMessages ); requireRight( d->m, Permissions::Expunge ); } if ( !permitted() ) return; if ( !transaction() ) { setTransaction( new Transaction( this ) ); Query * lock = new Query( "select * from mailboxes " "where id=$1 for update", 0 ); lock->bind( 1, d->m->id() ); transaction()->enqueue( lock ); d->messages = new Query( "select count(mm.uid)::bigint as messages " "from mailbox_messages mm " "join messages m on (mm.message=m.id) " "join mailboxes mb on (mm.mailbox=mb.id) " "where mm.mailbox=$1 and not mm.seen and " "(mm.uid>=mb.first_recent or m.idate>$2)", this ); d->messages->bind( 1, d->m->id() ); Date now; now.setCurrentTime(); d->messages->bind( 2, now.unixTime() - 20 ); transaction()->enqueue( d->messages ); transaction()->execute(); } if ( d->messages ) { if ( !d->messages->done() ) return; int64 messages = 0; Row * r = d->messages->nextRow(); if ( d->messages->failed() || !r ) error( No, "Could not determine if any messages exist" ); else messages = r->getBigint( "messages" ); if ( messages ) error( No, "Cannot delete mailbox: " + fn( messages ) + " messages exist" ); d->messages = 0; if ( ok() && d->m->remove( transaction() ) == 0 ) error( No, "Cannot delete mailbox " + d->m->name().ascii() ); Mailbox::refreshMailboxes( transaction() ); transaction()->commit(); } if ( !transaction()->done() ) return; if ( transaction()->failed() ) { error( No, "Database error: " + transaction()->error() ); return; } finish(); }
void Status::execute() { if ( state() != Executing ) return; // first part. set up. if ( !permitted() ) return; Session * session = imap()->session(); Mailbox * current = 0; if ( session ) current = session->mailbox(); // second part. see if anything has happened, and feed the cache if // so. make sure we feed the cache at once. if ( d->unseenCount || d->recentCount || d->messageCount ) { if ( d->unseenCount && !d->unseenCount->done() ) return; if ( d->messageCount && !d->messageCount->done() ) return; if ( d->recentCount && !d->recentCount->done() ) return; } if ( !::cache ) ::cache = new StatusData::StatusCache; if ( d->unseenCount ) { while ( d->unseenCount->hasResults() ) { Row * r = d->unseenCount->nextRow(); StatusData::CacheItem * ci = ::cache->find( r->getInt( "mailbox" ) ); if ( ci ) { ci->hasUnseen = true; ci->unseen = r->getInt( "unseen" ); } } } if ( d->recentCount ) { while ( d->recentCount->hasResults() ) { Row * r = d->recentCount->nextRow(); StatusData::CacheItem * ci = ::cache->find( r->getInt( "mailbox" ) ); if ( ci ) { ci->hasRecent = true; ci->recent = r->getInt( "recent" ); } } } if ( d->messageCount ) { while ( d->messageCount->hasResults() ) { Row * r = d->messageCount->nextRow(); StatusData::CacheItem * ci = ::cache->find( r->getInt( "mailbox" ) ); if ( ci ) { ci->hasMessages = true; ci->messages = r->getInt( "messages" ); } } } // third part. are we processing the first command in a STATUS // loop? if so, see if we ought to preload the cache. if ( mailboxGroup() && d->cacheState < 3 ) { IntegerSet mailboxes; if ( d->cacheState < 1 ) { // cache state 0: decide which messages List<Mailbox>::Iterator i( mailboxGroup()->contents() ); while ( i ) { StatusData::CacheItem * ci = ::cache->provide( i ); bool need = false; if ( d->unseen || d->recent || d->messages ) need = true; if ( ci->hasUnseen || ci->hasRecent || ci->hasMessages ) need = false; if ( need ) mailboxes.add( i->id() ); ++i; } if ( mailboxes.count() < 3 ) d->cacheState = 3; } if ( d->cacheState == 1 ) { // state 1: send queries if ( d->unseen ) { d->unseenCount = new Query( "select mailbox, count(uid)::int as unseen " "from mailbox_messages " "where mailbox=any($1) and not seen " "group by mailbox", this ); d->unseenCount->bind( 1, mailboxes ); d->unseenCount->execute(); } if ( d->recent ) { d->recentCount = new Query( "select id as mailbox, " "uidnext-first_recent as recent " "from mailboxes where id=any($1)", this ); d->recentCount->bind( 1, mailboxes ); d->recentCount->execute(); } if ( d->messages ) { d->messageCount = new Query( "select count(*)::int as messages, mailbox " "from mailbox_messages where mailbox=any($1) " "group by mailbox", this ); d->messageCount->bind( 1, mailboxes ); d->messageCount->execute(); } d->cacheState = 2; } if ( d->cacheState == 2 ) { // state 2: mark the cache as complete. IntegerSet mailboxes; List<Mailbox>::Iterator i( mailboxGroup()->contents() ); while ( i ) { StatusData::CacheItem * ci = ::cache->find( i->id() ); if ( ci && d->unseenCount ) ci->hasUnseen = true; if ( ci && d->recentCount ) ci->hasRecent = true; if ( ci && d->messageCount ) ci->hasMessages = true; ++i; } // and drop the queries d->cacheState = 3; d->unseenCount = 0; d->recentCount = 0; d->messageCount = 0; } } // the cache item we'll actually read from StatusData::CacheItem * i = ::cache->provide( d->mailbox ); // fourth part: send individual queries if there's anything we need if ( d->unseen && !d->unseenCount && !i->hasUnseen ) { d->unseenCount = new Query( "select $1::int as mailbox, " "count(uid)::int as unseen " "from mailbox_messages " "where mailbox=$1 and not seen", this ); d->unseenCount->bind( 1, d->mailbox->id() ); d->unseenCount->execute(); } if ( !d->recent ) { // nothing doing } else if ( d->mailbox == current ) { // we'll pick it up from the session } else if ( i->hasRecent ) { // the cache has it } else if ( !d->recentCount ) { d->recentCount = new Query( "select id as mailbox, " "uidnext-first_recent as recent " "from mailboxes where id=$1", this ); d->recentCount->bind( 1, d->mailbox->id() ); d->recentCount->execute(); } if ( !d->messages ) { // we don't need to collect } else if ( d->mailbox == current ) { // we'll pick it up } else if ( i->hasMessages ) { // the cache has it } else if ( d->messages && !d->messageCount ) { d->messageCount = new Query( "select count(*)::int as messages, " "$1::int as mailbox " "from mailbox_messages where mailbox=$1", this ); d->messageCount->bind( 1, d->mailbox->id() ); d->messageCount->execute(); } if ( d->unseenCount || d->recentCount || d->messageCount ) { if ( d->unseenCount && !d->unseenCount->done() ) return; if ( d->messageCount && !d->messageCount->done() ) return; if ( d->recentCount && !d->recentCount->done() ) return; } // fifth part: return the payload. EStringList status; if ( d->messages && i->hasMessages ) status.append( "MESSAGES " + fn( i->messages ) ); else if ( d->messages && d->mailbox == current ) status.append( "MESSAGES " + fn( session->messages().count() ) ); if ( d->recent && i->hasRecent ) status.append( "RECENT " + fn( i->recent ) ); else if ( d->recent && d->mailbox == current ) status.append( "RECENT " + fn( session->recent().count() ) ); if ( d->uidnext ) status.append( "UIDNEXT " + fn( d->mailbox->uidnext() ) ); if ( d->uidvalidity ) status.append( "UIDVALIDITY " + fn( d->mailbox->uidvalidity() ) ); if ( d->unseen && i->hasUnseen ) status.append( "UNSEEN " + fn( i->unseen ) ); if ( d->modseq ) { int64 hms = d->mailbox->nextModSeq(); // don't like this. an empty mailbox will have a STATUS HMS of // 1 before it receives its first message, and also 1 after. if ( hms > 1 ) hms--; status.append( "HIGHESTMODSEQ " + fn( hms ) ); } respond( "STATUS " + imapQuoted( d->mailbox ) + " (" + status.join( " " ) + ")" ); finish(); }
static UDP_Assoc *newUA(Connection *Conn,UDP_Assoc *uav[],PCStr(clhost),int clport,PCStr(svhost),int svport) { int ux; UDP_Assoc *ua; int svsock; int rcode; CStr(msg,128); CStr(lhost,256); int lport; CStr(local,256); CStr(remote,256); int SOCKSctl = -1; CStr(rh,256); int rp; rcode = -1; if( !permitted(clhost,clport,svhost,svport) ) return NULL; sprintf(local,"*:*"); sprintf(remote,"%s:%d",svhost,svport); Conn->from_cached = 1; VA_setClientAddr(Conn,clhost,clport,0); Conn->no_dstcheck_proto = serviceport("tcprelay"); initConnect(Conn); setupConnect(Conn); ServerFlags |= PF_UDP; Conn->sv.p_SOCKSCTL = -1; svsock = connectViaSocks(Conn,svhost,svport,AVStr(rh),&rp); if( 0 <= svsock ){ sv1log("via SOCKS UDP:%d@%s CTL:%d\n",svsock, Conn->sv.p_SOCKSADDR,Conn->sv.p_SOCKSCTL); SOCKSctl = Conn->sv.p_SOCKSCTL; goto ADDUA; } svsock = VSocket(Conn,"CNCT/UDPRELAY",-1,AVStr(local),AVStr(remote),""); if( 0 <= svsock ){ /* setNonblockingIO("UDPRELAY-SV",svsock,1); */ SetNonblockingIO("UDPRELAY-SV",svsock,1); goto ADDUA; } strcpy(lhost,"*"); lport = 0; SRCIFfor(Conn,"udprelay",svhost,svport,AVStr(lhost),&lport); if( strcmp(lhost,"*") == 0 ) lhost[0] = 0; svsock = server_open("UDPRELAY",AVStr(lhost),lport,-1); if( svsock < 0 ){ if( uav[0] == 0 ){ return NULL; } ux = longestIdle(uav); sv1log("push out longest idle 1 [%d]\n",ux); delUA(uav,ux,"NoMoreSocket",1); svsock = server_open("UDPRELAY",AVStr(lhost),lport,-1); if( svsock < 0 ) return NULL; } if( UDPRELAY_RPORT_FIX ){ rcode = __connectServer(svsock,"UDPRELAY","udprelay",svhost,svport /*,1*/); if( rcode < 0 ){ sv1log("UDPRELAY: connect(%d) error %d\n",svsock,rcode); close(svsock); return NULL; } } ADDUA: for( ux = 0; uav[ux]; ux++ ) ; if( UDPRELAY_MAXASSOC <= ux ){ ux = longestIdle(uav); sv1log("push out longest idle 2 [%d]\n",ux); delUA(uav,ux,"NoMoreClient",0); } ua = (UDP_Assoc*)calloc(1,sizeof(UDP_Assoc)); ua->ua_id = ++uaid; ua->ua_ctime = time(0); ua->ua_clhost = stralloc(clhost); ua->ua_clport = clport; ua->ua_svsock = svsock; ua->ua_svbound = (0 < peerPort(svsock)); ua->ua_svtcp = !isUDPsock(svsock); ua->ua_svhost = stralloc(svhost); ua->ua_svport = svport; ua->ua_svSOCKS = SOCKSctl; VSA_aptosa(&ua->ua_SOCKSADDR,Conn->sv.p_SOCKSADDR); uav[ux] = ua; msghead(AVStr(msg),"start",ua,ux); sv1log("%s > %s:%d\n",msg,svhost,svport); return ua; }