daemon/stat.cc
author "Tomas Zeman <tzeman@volny.cz>"
Sun, 20 Jan 2008 00:22:25 +0100
changeset 3 3d1d327cfa68
parent 2 b3afb9f1e801
permissions -rw-r--r--
vmailmgr-0.97

// Copyright (C) 1999,2000 Bruce Guenter <bruceg@em.ca>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include <config.h>
#include <stdlib.h>
#include "daemon.h"
#include "misc/pwentry.h"
#include "misc/lookup.h"
#include "misc/utoa.h"
#include "misc/stat_fns.h"
#include "ac/dirent.h"

struct count_size
{
  unsigned long count;
  unsigned long size;
  count_size() : count(0), size(0) { }
};

struct stats
{
  count_size unseen_new;
  count_size unseen;
  count_size seen;
  
  mystring rep() const;
};

mystring stats::rep() const
{
  return utoa(unseen_new.count) + mystring::NUL +
    utoa(unseen_new.size)  + mystring::NUL + 
    utoa(unseen.count) + mystring::NUL +
    utoa(unseen.size) + mystring::NUL +
    utoa(seen.count) + mystring::NUL +
    utoa(seen.size) + mystring::NUL;
}

class statdir
{
  mystring path;
  DIR* dir;
  struct dirent* curr;
  struct stat statbuf;
public:
  statdir(const mystring& dirname);
  ~statdir() { close(); }
  void close();
  operator void*() const { return (void*)dir; }
  bool operator!() const { return !dir; }
  const struct stat* operator->() const { return &statbuf; }
  const char* currname() const { return curr->d_name; }
  void operator++() { advance(); }
  void advance();
};

statdir::statdir(const mystring& dirname)
  : path(dirname),
    dir(opendir(dirname.c_str()))
{
  advance();
}
  
void statdir::close()
{
  if(dir)
    closedir(dir);
  dir = NULL;
}

void statdir::advance()
{
  if(dir) {
    while((curr = readdir(dir)) != 0) {
      if(curr->d_name[0] == '.')
	continue;
      break;
    }
  }
  if(!curr)
    close();
  else {
    mystring fullpath = path + "/" + curr->d_name;
    if(stat(fullpath.c_str(), &statbuf) == -1)
      close();
  }
}
    
bool stat_new_dir(const mystring& basename, stats& stats)
{
  statdir dir(basename + "/new");
  if(!dir)
    return false;
  while(dir) {
    if(S_ISREG(dir->st_mode)) {
      ++stats.unseen_new.count;
      stats.unseen_new.size += dir->st_blocks * 512;
    }
    ++dir;
  }
  return true;
}

bool stat_cur_dir(const mystring& basename, stats& stats)
{
  statdir dir(basename + "/cur");
  if(!dir)
    return false;
  while(dir) {
    if(S_ISREG(dir->st_mode)) {
      count_size* stat = &stats.unseen;
      const char* colon = strchr(dir.currname(), ':');
      if(colon) {
	++colon;
	if(*colon++ == '2' && *colon++ == ',' && !strchr(colon, 'S'))
	  stat = &stats.seen;
      }
      ++stat->count;
      stat->size += dir->st_blocks * 512;
    }
    ++dir;
  }
  return true;
}

bool stat_dir(const mystring& basename, stats& stats)
{
  return stat_new_dir(basename, stats) &&
    stat_cur_dir(basename, stats);
}

CMD(stat)
  // Usage: stat baseuser-virtuser pass
{
  mystring user = args[0];
  mystring pass = args[1];

  pwentry* pw;
  vpwentry* vpw;

  OK_RESPONSE(lookup_and_validate(user, pw, vpw, pass, true, false));

  if(!vpw->has_mailbox)
    RETURN(err, "User is alias");

  mystring dirname = pw->home + "/" + vpw->directory;
  stats stats;
  if(!stat_dir(dirname, stats))
    RETURN(err, "Failed to stat maildir");

  RETURN(ok, mystring::NUL + stats.rep());
}