/*
 * Copyright (c) 1986, 1987, 1988 by The Trustees of Columbia University
 * in the City of New York.  Permission is granted to any individual or
 * institution to use, copy, or redistribute this software so long as it
 * is not sold for profit, provided this copyright notice is retained.
 */

#ifndef lint
static char *rcsid = "$Header: misc.c,v 1.47 88/07/22 16:29:06 chris Exp $";
#endif

/*
 * misc.c - miscellaneous commands
 */

#include "mm.h"
#include "parse.h"
#include "help.h"
#include "rd.h"

#ifdef HAVE_QUOTAS
#   ifdef HAVE_QUOTACTL
#	include <ufs/quota.h>
#   else
#	include <sys/quota.h>
#   endif
#endif


int
cmd_version (n)
int n;
{
    confirm ();
    printf ("%s\n", mm_version);
    puts("Copyright (c) 1986, 1987, 1988\n\
\tThe Trustees of Columbia University in the City of New York");
    printf ("Compiled %s\n", mm_compiled);
    printf ("Report bugs to %s\n", BUGSTO);
}

#ifdef HAVE_QUOTAS
#define ST_GOODQUOTA 0
#define ST_BADQUOTA  1
#define ST_NOQUOTA   2
#endif

int
cmd_status (n)
int n;
{
    int verbose = FALSE;
#ifdef HAVE_QUOTAS
    int quotaflag = ST_GOODQUOTA;
    struct dqblk qblk;
#endif
    struct stat sbuf;
    static fdb conffdb = { _CMCFM, CM_SDH, NULL, NULL, 
			       "confirm for status summary ", 
			       NULL, NULL};
    static keywrd ver_key[] = {
    	{ "verbose", 0 , (keyval) 0 },
    };
    static keytab vertab = { sizeof (ver_key) / sizeof (keywrd),
			      ver_key };
    static fdb verswi = { _CMKEY, 0, NULL, (pdat) &vertab };


    parse (fdbchn (&verswi, &conffdb, NULL), &pv, &used);
    if (used == &verswi) {
	confirm();
	verbose = TRUE;
    }

    show_route(TRUE);			/* show mail routing */

    if (cf) {
	int i, nrec = 0, ndel = 0, nuns = 0;
	for (i = 0; i < cf->count; i++)	{
	    if (cf->msgs[i+1].flags & M_DELETED)
		ndel++;
	    if (cf->msgs[i+1].flags & M_RECENT)
		nrec++;
	    if (!(cf->msgs[i+1].flags & M_SEEN))
		nuns++;
	}
	printf (" File %s (%s%s%s)\n",cf->filename, msg_ops[cf->type].typename,
		(cf->flags&(MF_DIRTY|MF_MODIFIED) ? ", modified" : ""),
		(cf->flags&MF_RDONLY) ? ", read-only" : "");
	printf (" %d messages, %d old, %d deleted, %d unseen, %dk Bytes\n",
		cf->count, cf->count - nrec, ndel, nuns, (cf->size+512)/1024);
	printf (" Currently at message %d\n", cf->current);
    }
    else
	printf (" No current mail file\n");
    if (!verbose)
	return;				/* done */
#ifdef HAVE_QUOTAS
    if (cf == NULL)
	quotaflag = ST_NOQUOTA;
    else {
	if (fstat (fileno(cf->filep), &sbuf) != 0) {
	    perror (cf->filename);
	    quotaflag = ST_BADQUOTA;
	}
	else if (
#ifdef HAVE_QUOTACTL
 		 quotactl (Q_GETQUOTA, UID, (int) sbuf.st_dev, &qblk)
#else
		 quota (Q_GETDLIM, UID, (int) sbuf.st_dev, &qblk) 
#endif
		 != 0)
	    quotaflag = ST_NOQUOTA;	/* assume this, random error codes */
	if (quotaflag != ST_NOQUOTA) {
	    printf (" Blocks free: ");
	    if (quotaflag == ST_BADQUOTA)
		printf ("unknown\n");
	    else {				/* ST_GOODQUOTA */
		u_long i;
		i = qblk.dqb_bhardlimit - qblk.dqb_curblocks;
		printf ("%ld (%ld kb)\n", i, (dbtob(i)>>10)); /* 2^10 = 1 kb */
	    }
	}
    }
#endif
    printf (" User: %s <%s@%s>\n", 
	    real_personal_name ? real_personal_name : "",
	    user_name, fullhostname);
    printf (" Process ID = %d, User ID = %d\n", PID, UID);
}

blank ()
{
    if (cmcsb._cmoj)
	return (cmcls ());
    /* XXX shouldn't have to do it this way, but cmcsb._cmoj is
       NULL when we're throwing away output inside init files, but
       we want to let users clear the screen in that context */
    cmcsb._cmoj = stdout;
    cmcls();
    cmcsb._cmoj = (FILE *) NULL;
}

int
cmd_blank (cmd)
int cmd;
{
    confirm ();
    blank ();
}

int
cmd_daytime (n)
int n;
{
    buffer buf;

    static fdb seq_fdb_tad = { _CMTAD };

    parse (fdbchn (&seq_fdb_tad, &cfm_fdb, nil), &pv, &used);
    if (used == &seq_fdb_tad) {
	time_t t = datimetogmt (&pv._pvtad);
	confirm ();
	printf ("Local time: %s\n", daytime (t));
	return;
    }
    printf ("%s\n", daytime ((time_t) 0));
}

int
cmd_echo (n)
int n;
{
    parse_text ("string to echo", nil);
    printf ("%s\n", atmbuf);
}

ustrncmp(str1, str2, n)
char *str1, *str2;
int n;
{
    char s1, s2;
    while(n > 0) {
 	s1 = islower(*str1) ? toupper(*str1) : *str1;
 	s2 = islower(*str2) ? toupper(*str2) : *str2;

	if (s1 == s2) {
	    if (s1 == '\0') return(0);
	    else {
		str1++; str2++; n--;
	    }
	    continue;
	}
	if (s1 > s2) return(1);
	if (s1 < s2) return(-1);
    }
    return(0);
}

int 
cmd_cd (n)
int n;
{
    pval parseval;			/* ccmd parse return structure */
    fdb *used;				/* which fdb was used */
    static fdb conffdb = { _CMCFM, CM_SDH, NULL, NULL, 
			       "confirm to connect to your home directory", 
			       NULL, NULL};
    static fdb dirfdb = { _CMFIL, FIL_DIR|FIL_SDH, 
			      NULL, NULL, "directory", NULL, NULL };

    noise ("to directory");

    dirfdb._cmdef = HOME;		/* set default */
    parse (fdbchn(&dirfdb,&conffdb,NULL), &parseval, &used);
    if (used == &dirfdb) {
	confirm();
	if (chdir (parseval._pvfil[0]) != 0) {
	    perror ("cd");
	    return;
	}
	return;
    }
    /* else cd to HOME */
    if (HOME == NULL) {
	fprintf (stderr, "Can't find home directory.\n");
	return;
    }
    if (chdir (HOME) != 0) {
	perror ("cd");
	return;
    }
}


int
cmd_pwd (n)
int n;
{
  char wd[MAXPATHLEN];
  char *getwd();

  confirm();
  if (getwd(wd) == NULL) {
    fprintf (stderr, "%s\n", wd);
    return;
  }
  else
    printf ("%s\n", wd);
}


msgcmp(a,b)
message *a, *b;
{
    if (a->date < b->date)
	return(-1);
    if (a->date > b->date)
	return(1);
    return(0);
}

#define CS (cf->sequence)
#define PS (cf->prev_sequence)
#define RS (cf->read_sequence)

cmd_sort(n)
{
    int i;

    if (!check_cf(true))		/* can't modify it */
	return;
    noise ("chronologically");
    confirm();
    qsort(&cf->msgs[1], cf->count, sizeof(message), msgcmp);
    clear_sequence(CS);
    clear_sequence(RS);
    clear_sequence(PS);
    cf->flags |= MF_DIRTY;
    for(i = 0; i < cf->count; i++)
	cf->msgs->flags |= M_MODIFIED;
}

cmd_alias (n)
int n;
{
    confirm();
    printhelp (n, HELP_TOP);
}

char *
safe_realloc(cp, size)
char *cp;
int size;
{
    char *realloc(), *malloc();

    if (cp)
	return(realloc(cp,size));
    else
	return(malloc(size));
}
