/* 
 * $Id: util.c,v 1.4.2.7 2006/02/05 16:49:08 tomcollins Exp $
 * Copyright (C) 1999-2004 Inter7 Internet Technologies, Inc. 
 *
 * 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <dirent.h>
#include <ctype.h>

#include <vpopmail.h>

#include "alias.h"
#include "autorespond.h"
#include "config.h"
#include "forward.h"
#include "mailinglist.h"
#include "qmailadmin.h"
#include "qmailadminx.h"
#include "printh.h"
#include "user.h"
#include "util.h"

extern FILE *lang_fs;
extern FILE *color_table;

#define SORT_TABLE_ENTRIES 100000

/* pointer to array of pointers */
unsigned char **sort_list;

unsigned char *sort_block[200]; /* memory blocks for sort data */
int memleft, memindex, sort_entry;
char *sort_ptr;

int sort_init ()
{
  sort_entry = memindex = memleft = 0;
  sort_list = malloc(SORT_TABLE_ENTRIES * sizeof(char *));
  if (!sort_list) { return -1; }
  return 0;
}
/* add entry to list for sorting, copies string until it gets to char 
   'end' */
int sort_add_entry (char *entry, char end)
{
  int len;

  if (sort_entry == SORT_TABLE_ENTRIES) {
    return -2;   /* table is full */
  }
  if (memleft < 256)
  {
    /* allocate a 64K block of memory to store table entries */
    memleft = 65536;
    sort_ptr = sort_block[memindex++] = malloc(memleft);
  }
  if (!sort_ptr) { return -1; }
  sort_list[sort_entry++] = sort_ptr;
  len = 1;   /* at least a terminator */
  while (*entry && *entry != end) {
    *sort_ptr++ = *entry++;
    len++;
  }
  *sort_ptr++ = 0;  /* NULL terminator */
  memleft -= len;
  return 0;
}
char *sort_get_entry(int index)
{
  if ((index < 0) || (index >= sort_entry)) { return NULL; }
  return sort_list[index];
}
void sort_cleanup()
{
  while (memindex) { free (sort_block[--memindex]); }
  if (sort_list) {
    free (sort_list);
    sort_list = NULL;
  }
}
/* Comparison routine used in qsort for multiple functions */
static int sort_compare (const void *p1, const void *p2)
{
  return strcasecmp (*(char **)p1, *(char **)p2);
} 
void sort_dosort()
{
  qsort (sort_list, sort_entry, sizeof(char *), sort_compare);
}

void str_replace (char *s, char orig, char repl)
{
  while (*s) {
    if (*s == orig) { *s = repl; }
    s++;
  }
}

void qmail_button(char *modu, char *command, char *user, char *dom, time_t mytime, char *png)    
{
  printf ("<td align=center>");
  printh ("<a href=\"%s/com/%s?user=%C&dom=%C&time=%d&modu=%C\">",
    CGIPATH, command, user, dom, mytime, modu);
  printf ("<img src=\"%s/%s\" border=0></a>", IMAGEURL, png);
  printf ("</td>\n");
}

int check_local_user( user )
 char *user;
{
 struct stat buf;
 int i,j;

  /* check for aliases and autoresponders */
  if ( valias_select (user, Domain)) return(-1);

  /* check for mailing list */
  strcpy(TmpBuf, ".qmail-");
  for(i=0,j=7;user[i]!=0;++i,++j){
    if ( user[i] == '.' ) TmpBuf[j] = ':'; 
    else TmpBuf[j] = user[i];
  }
  TmpBuf[j] = 0;
  if ( stat(TmpBuf, &buf) == 0 ) return(-1);

  /* check for POP/IMAP user */
  if ( vauth_getpw(user, Domain)) return(-1);

  return(0);
}

void show_counts()
{
  count_users();
  count_forwards();
  count_autoresponders();
  count_mailinglists();

  printf ("%s = %d<BR>\n", html_text[61], CurPopAccounts);
  printf ("%s = %d<BR>\n", html_text[74], CurForwards);
  printf ("%s = %d<BR>\n", html_text[77], CurAutoResponders);
  printf ("%s = %d<BR>\n", html_text[80], CurMailingLists);
}

/* check_email_addr( char *addr )
 *
 * Make sure 'addr' is a valid email address.  Returns 1 if it's bad,
 * 0 if it's good.
 */
int check_email_addr( char *addr )
{
 char *taddr = addr;
 char *atpos = NULL;
 char *dotpos = NULL;

  for(taddr = addr; *taddr != '\0'; ++taddr) {
    if (*taddr == '@') {
      if (atpos != NULL) return 1; /* double @ */
      atpos = taddr;
    } else if(!isalnum(*taddr) && (strchr (".-+=_&", *taddr) == NULL)) {
      return 1;
    }
  }

  /* if just a user name with no @domain.com then bad */
  if (atpos == NULL) return 1;

  /* Look for a sub domain */
  dotpos = strchr (atpos, '.');

  /* no '.' in the domain part */
  if (dotpos == NULL) return 1;

  /* once we know it's good, convert it to lowercase */
  lowerit(addr);

  return 0;
}

int fixup_local_name( addr )
 char *addr;
{
 char *taddr = addr;

  /* don't allow zero length user names */
  if(strlen(taddr)<=0) return(1);

  /* force it to lower case */
  lowerit(addr);

  /* check for valid email address */
  for(taddr=addr;*taddr!=0;++taddr) {

    if(!isalnum(*taddr) && !ispunct(*taddr)) return(1);
    if(isspace(*taddr)) return(1);

    if(ispunct(*taddr)&& (strchr (".-+=_&", *taddr) == NULL)){
      return(1);
    }
  }

  /* if we made it here, everything is okay */
  return(0);
}

void ack(msg, extra)
 char *msg;
 char *extra;
{
  printf ("%s %s\n", get_html_text(msg), extra);
  printf ("</BODY></HTML>\n");
  vclose();
  exit(0);
}

void upperit( instr )
 char *instr;
{
  while(*instr!=0) {
    if ( islower(*instr) ) *instr = toupper(*instr);
    ++instr;
  }
}

char *safe_getenv(char *var)
{
 char *s;

  s = getenv(var);
  if ( s == NULL ) return("");
  return(s);
}

char *strstart(sstr, tstr)
 char *sstr;
 char *tstr;
{
 char *ret_str;

  ret_str = sstr;
  if ( sstr == NULL || tstr == NULL ) return(NULL);

  while ( *sstr != 0 && *tstr != 0 ) {
    if ( *sstr != *tstr ) return(NULL);
    ++sstr;
    ++tstr;
  }

  if ( *tstr == 0 ) return(ret_str);
  return(NULL);

}

int open_lang(char *lang)
{
  char langfile[200];
  static char *langpath = NULL;
  struct stat mystat;

  /* do not read lang files with path control characters */
  if ( strstr(lang,".")!=NULL || strstr(lang,"/")!=NULL ) return(-1);

  /* convert to lower case (using lowerit() from libvpopmail) */
  lowerit(lang);

  /* close previous language if still open */
  if (lang_fs != NULL) fclose (lang_fs);

  if (langpath == NULL) {
    langpath = getenv(QMAILADMIN_TEMPLATEDIR);
    if (langpath == NULL ) langpath = HTMLLIBDIR;
  }

  snprintf(langfile, sizeof(langfile), "%s/lang/%s", langpath, lang);

  /* do not open symbolic links */
  if (lstat(langfile, &mystat)==-1 || S_ISLNK(mystat.st_mode)) return(-1);

  if ( (lang_fs=fopen(langfile, "r"))==NULL) return(-1);

  return(0);
}

char *get_html_text( char *index )
{
  return html_text[atoi(index)];
}

int open_colortable()
{
 char tmpbuf[200];
 char *tmpstr;

  tmpstr = getenv(QMAILADMIN_TEMPLATEDIR);
  if (tmpstr == NULL ) tmpstr = HTMLLIBDIR;

  snprintf(tmpbuf, sizeof(tmpbuf), "%s/html/colortable", tmpstr);
  if ( (color_table=fopen(tmpbuf, "r"))==NULL) return(-1);
  return(0);
}

char *get_color_text( char *index )
{
 static char tmpbuf[400];
 char *tmpstr;

  if (color_table == NULL) return("");

  rewind(color_table);
  while(fgets(tmpbuf,sizeof(tmpbuf),color_table)!=NULL){
    tmpstr = strtok(tmpbuf, " ");
    if (strcmp(tmpstr, index) == 0 ) {
      tmpstr = strtok(NULL, "\n");
      return(tmpstr);
    }    
  }
  return("");
}
/* bk - use maildir++ quotas now
char *get_quota_used(char *dir) {
    static char tmpbuff[40];
    double size;

    size = get_du(dir);
    if (size > 0) {
        size = size / 1048576; 
    }
    sprintf(tmpbuff, "%.2lf", size);
    return tmpbuff;
}
*/
/* quota_to_bytes: used to convert user entered quota (given in MB)
                   back to bytes for vpasswd file
   return value: 0 for success, 1 for failure
*/
int quota_to_bytes(char returnval[], char *quota) {
    double tmp;

    if (quota == NULL) { return 1; }
    if ((tmp = atof(quota))) {
        tmp *= 1048576;
        sprintf(returnval, "%.0lf", tmp);
        return 0;
    } else {
	strcpy (returnval, "");
	return 1;
    }
}
/* quota_to_megabytes: used to convert vpasswd representation of quota
                       to number of megabytes.
   return value: 0 for success, 1 for failure
*/
int quota_to_megabytes(char *returnval, char *quota) {
    double tmp;
    int i;

    if (quota == NULL) { return 1; }
    i = strlen(quota);
    if ((quota[i-1] == 'M') || (quota[i-1] == 'm')) {
        tmp = atol(quota);  /* already in megabytes */
    } else if ((quota[i-1] == 'K') || (quota[i-1] == 'k')) {
	tmp = atol(quota) * 1024;  /* convert kilobytes to megabytes */
    } else if ((tmp = atol(quota))) {
        tmp /= 1048576.0;
    } else {
	strcpy (returnval, "");
	return 1;
    }
    sprintf(returnval, "%.2lf", tmp);
    return 0;
}

void print_user_index (char *action, int colspan, char *user, char *dom, time_t mytime)
{
#ifdef USER_INDEX
  int k;

  printf ("<tr bgcolor=%s>", get_color_text("000"));
  printf ("<td colspan=%d align=\"center\">", colspan);
  printf ("<hr>");
  printf ("<b>%s</b> &nbsp; ", html_text[133]);
  for (k = 0; k < 10; k++) {
	printh ("<a href=\"%s/com/%s?user=%C&dom=%C&time=%d&searchuser=%d\">%d</a>\n",
	  CGIPATH, action, user, dom, mytime, k, k);
  }
  for (k = 'a'; k <= 'z'; k++) {
	printh ("<a href=\"%s/com/%s?user=%C&dom=%C&time=%d&searchuser=%c\">%c</a>\n",
	  CGIPATH, action, user, dom, mytime, k, k);
  }
  printf ("</td>");
  printf ("</tr>\n");

  printf ("<tr bgcolor=%s>", get_color_text("000"));
  printf ("<td colspan=%d>", colspan);
  printf ("<table border=0 cellpadding=3 cellspacing=0 width=\"100%%\"><tr><td align=\"center\"><br>");
  printf ("<form method=\"get\" action=\"%s/com/%s\">", CGIPATH, action);
  printh ("<input type=\"hidden\" name=\"user\" value=\"%H\">", user);
  printh ("<input type=\"hidden\" name=\"dom\" value=\"%H\">", dom);
  printf ("<input type=\"hidden\" name=\"time\" value=\"%u\">", (unsigned int) mytime);
  printh ("<input type=\"text\" name=\"searchuser\" value=\"%H\">&nbsp;", SearchUser);
  printf ("<input type=\"submit\" value=\"%s\">", html_text[204]);
  printf ("</form>");
  printf ("</td></tr></table>");
  printf ("<hr>");
  printf ("</td></tr>\n");

#endif
}

/*
 * Brian Kolaci
 * updated function that doesn't require fts_*
 */
/* bk - use maildir++ quotas now
off_t get_du(const char *dir_name)
{
  DIR *dirp;
  struct dirent *dp;
  struct stat statbuf;
  off_t file_size = 0;
  char *tmpstr;

  if (dir_name == NULL)
    return 0;

  if (chdir(dir_name) == -1)
    return 0;

  if ((dirp = opendir(".")) == NULL)
    return 0;

  while ((dp=readdir(dirp)) != NULL) {
    if (!strcmp(dp->d_name, "..") || !strcmp(dp->d_name, "."))
      continue;
    if ((tmpstr=strstr(dp->d_name, ",S=")) != NULL) {
      file_size += atol(tmpstr+3);
    } else if (stat(dp->d_name,&statbuf)==0 && (statbuf.st_mode & S_IFDIR) ) {
      file_size += get_du(dp->d_name);
    }
  }
  closedir(dirp);
  if (dir_name != NULL && strcmp(dir_name, ".." ) && strcmp(dir_name, "." ))
    chdir("..");
  return(file_size);
}
*/


syntax highlighted by Code2HTML, v. 0.9.1