1 /*
2  * $Id: util.c,v 1.4.2.10 2009/05/02 18:22:25 tomcollins Exp $
3  * Copyright (C) 1999-2004 Inter7 Internet Technologies, Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18  */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <pwd.h>
27 #include <dirent.h>
28 #include <ctype.h>
29 
30 #include <vpopmail.h>
31 
32 #include "alias.h"
33 #include "autorespond.h"
34 #include "config.h"
35 #include "forward.h"
36 #include "mailinglist.h"
37 #include "qmailadmin.h"
38 #include "qmailadminx.h"
39 #include "printh.h"
40 #include "user.h"
41 #include "util.h"
42 
43 extern FILE *lang_fs;
44 extern FILE *color_table;
45 
46 #define SORT_TABLE_ENTRIES 100000
47 
48 /* pointer to array of pointers */
49 unsigned char **sort_list;
50 
51 unsigned char *sort_block[200]; /* memory blocks for sort data */
52 int memleft, memindex, sort_entry;
53 char *sort_ptr;
54 
sort_init()55 int sort_init ()
56 {
57   sort_entry = memindex = memleft = 0;
58   sort_list = malloc(SORT_TABLE_ENTRIES * sizeof(char *));
59   if (!sort_list) { return -1; }
60   return 0;
61 }
62 /* add entry to list for sorting, copies string until it gets to char
63    'end' */
sort_add_entry(char * entry,char end)64 int sort_add_entry (char *entry, char end)
65 {
66   int len;
67 
68   if (sort_entry == SORT_TABLE_ENTRIES) {
69     return -2;   /* table is full */
70   }
71   if (memleft < 256)
72   {
73     /* allocate a 64K block of memory to store table entries */
74     memleft = 65536;
75     sort_ptr = sort_block[memindex++] = malloc(memleft);
76   }
77   if (!sort_ptr) { return -1; }
78   sort_list[sort_entry++] = sort_ptr;
79   len = 1;   /* at least a terminator */
80   while (*entry && *entry != end) {
81     *sort_ptr++ = *entry++;
82     len++;
83   }
84   *sort_ptr++ = 0;  /* NULL terminator */
85   memleft -= len;
86   return 0;
87 }
sort_get_entry(int index)88 char *sort_get_entry(int index)
89 {
90   if ((index < 0) || (index >= sort_entry)) { return NULL; }
91   return sort_list[index];
92 }
sort_cleanup()93 void sort_cleanup()
94 {
95   while (memindex) { free (sort_block[--memindex]); }
96   if (sort_list) {
97     free (sort_list);
98     sort_list = NULL;
99   }
100 }
101 /* Comparison routine used in qsort for multiple functions */
sort_compare(const void * p1,const void * p2)102 static int sort_compare (const void *p1, const void *p2)
103 {
104   return strcasecmp (*(char **)p1, *(char **)p2);
105 }
sort_dosort()106 void sort_dosort()
107 {
108   qsort (sort_list, sort_entry, sizeof(char *), sort_compare);
109 }
110 
str_replace(char * s,char orig,char repl)111 void str_replace (char *s, char orig, char repl)
112 {
113   while (*s) {
114     if (*s == orig) { *s = repl; }
115     s++;
116   }
117 }
118 
qmail_button(char * modu,char * command,char * user,char * dom,time_t mytime,char * png)119 void qmail_button(char *modu, char *command, char *user, char *dom, time_t mytime, char *png)
120 {
121   printf ("<td align=center>");
122   printh ("<a href=\"%s&modu=%C\">", cgiurl(command), modu);
123   printf ("<img src=\"%s/%s\" border=0></a>", IMAGEURL, png);
124   printf ("</td>\n");
125 }
126 
check_local_user(user)127 int check_local_user( user )
128  char *user;
129 {
130  struct stat buf;
131  int i,j;
132 
133   /* check for aliases and autoresponders */
134   if ( valias_select (user, Domain)) return(-1);
135 
136   /* check for mailing list */
137   strcpy(TmpBuf, ".qmail-");
138   for(i=0,j=7;user[i]!=0;++i,++j){
139     if ( user[i] == '.' ) TmpBuf[j] = ':';
140     else TmpBuf[j] = user[i];
141   }
142   TmpBuf[j] = 0;
143   if ( stat(TmpBuf, &buf) == 0 ) return(-1);
144 
145   /* check for POP/IMAP user */
146   if ( vauth_getpw(user, Domain)) return(-1);
147 
148   return(0);
149 }
150 
show_counts()151 void show_counts()
152 {
153   count_users();
154   count_forwards();
155   count_autoresponders();
156   count_mailinglists();
157 
158   printf ("%s = %d<BR>\n", html_text[61], CurPopAccounts);
159   printf ("%s = %d<BR>\n", html_text[74], CurForwards);
160   printf ("%s = %d<BR>\n", html_text[77], CurAutoResponders);
161   printf ("%s = %d<BR>\n", html_text[80], CurMailingLists);
162 }
163 
164 /* check_email_addr( char *addr )
165  *
166  * Make sure 'addr' is a valid email address.  Returns 1 if it's bad,
167  * 0 if it's good.
168  */
check_email_addr(char * addr)169 int check_email_addr( char *addr )
170 {
171  char *taddr = addr;
172  char *atpos = NULL;
173  char *dotpos = NULL;
174 
175   for(taddr = addr; *taddr != '\0'; ++taddr) {
176     if (*taddr == '@') {
177       if (atpos != NULL) return 1; /* double @ */
178       atpos = taddr;
179     } else if(!isalnum(*taddr) && (strchr (".-+=_&", *taddr) == NULL)) {
180       return 1;
181     }
182   }
183 
184   /* if just a user name with no @domain.com then bad */
185   if (atpos == NULL) return 1;
186 
187   /* Look for a sub domain */
188   dotpos = strchr (atpos, '.');
189 
190   /* no '.' in the domain part */
191   if (dotpos == NULL) return 1;
192 
193   /* once we know it's good, convert it to lowercase */
194   lowerit(addr);
195 
196   return 0;
197 }
198 
fixup_local_name(addr)199 int fixup_local_name( addr )
200  char *addr;
201 {
202  char *taddr = addr;
203 
204   /* don't allow zero length user names */
205   if(strlen(taddr)<=0) return(1);
206 
207   /* force it to lower case */
208   lowerit(addr);
209 
210   /* check for valid email address */
211   for(taddr=addr;*taddr!=0;++taddr) {
212 
213     if(!isalnum(*taddr) && !ispunct(*taddr)) return(1);
214     if(isspace(*taddr)) return(1);
215 
216     if(ispunct(*taddr)&& (strchr (".-+=_&", *taddr) == NULL)){
217       return(1);
218     }
219   }
220 
221   /* if we made it here, everything is okay */
222   return(0);
223 }
224 
ack(msg,extra)225 void ack(msg, extra)
226  char *msg;
227  char *extra;
228 {
229   printf ("%s %s\n", get_html_text(msg), extra);
230   printf ("</BODY></HTML>\n");
231   vclose();
232   exit(0);
233 }
234 
upperit(instr)235 void upperit( instr )
236  char *instr;
237 {
238   while(*instr!=0) {
239     if ( islower(*instr) ) *instr = toupper(*instr);
240     ++instr;
241   }
242 }
243 
safe_getenv(char * var)244 char *safe_getenv(char *var)
245 {
246  char *s;
247 
248   s = getenv(var);
249   if ( s == NULL ) return("");
250   return(s);
251 }
252 
strstart(sstr,tstr)253 char *strstart(sstr, tstr)
254  char *sstr;
255  char *tstr;
256 {
257  char *ret_str;
258 
259   ret_str = sstr;
260   if ( sstr == NULL || tstr == NULL ) return(NULL);
261 
262   while ( *sstr != 0 && *tstr != 0 ) {
263     if ( *sstr != *tstr ) return(NULL);
264     ++sstr;
265     ++tstr;
266   }
267 
268   if ( *tstr == 0 ) return(ret_str);
269   return(NULL);
270 
271 }
272 
open_lang(char * lang)273 int open_lang(char *lang)
274 {
275   char langfile[200];
276   static char *langpath = NULL;
277   struct stat mystat;
278 
279   /* do not read lang files with path control characters */
280   if ( strchr(lang,'.')!=NULL || strchr(lang,'/')!=NULL ) return(-1);
281 
282   /* convert to lower case (using lowerit() from libvpopmail) */
283   lowerit(lang);
284 
285   /* close previous language if still open */
286   if (lang_fs != NULL) fclose (lang_fs);
287 
288   if (langpath == NULL) {
289     langpath = getenv(QMAILADMIN_TEMPLATEDIR);
290     if (langpath == NULL ) langpath = HTMLLIBDIR;
291   }
292 
293   snprintf(langfile, sizeof(langfile), "%s/lang/%s", langpath, lang);
294 
295   /* do not open symbolic links */
296   if (lstat(langfile, &mystat)==-1 || S_ISLNK(mystat.st_mode)) return(-1);
297 
298   if ( (lang_fs=fopen(langfile, "r"))==NULL) return(-1);
299 
300   return(0);
301 }
302 
get_html_text(char * index)303 char *get_html_text( char *index )
304 {
305   return html_text[atoi(index)];
306 }
307 
open_colortable()308 int open_colortable()
309 {
310  char tmpbuf[200];
311  char *tmpstr;
312 
313   tmpstr = getenv(QMAILADMIN_TEMPLATEDIR);
314   if (tmpstr == NULL ) tmpstr = HTMLLIBDIR;
315 
316   snprintf(tmpbuf, sizeof(tmpbuf), "%s/html/colortable", tmpstr);
317   if ( (color_table=fopen(tmpbuf, "r"))==NULL) return(-1);
318   return(0);
319 }
320 
get_color_text(char * index)321 char *get_color_text( char *index )
322 {
323  static char tmpbuf[400];
324  char *tmpstr;
325 
326   if (color_table == NULL) return("");
327 
328   rewind(color_table);
329   while(fgets(tmpbuf,sizeof(tmpbuf),color_table)!=NULL){
330     tmpstr = strtok(tmpbuf, " ");
331     if (strcmp(tmpstr, index) == 0 ) {
332       tmpstr = strtok(NULL, "\n");
333       return(tmpstr);
334     }
335   }
336   return("");
337 }
338 /* bk - use maildir++ quotas now
339 char *get_quota_used(char *dir) {
340     static char tmpbuff[40];
341     double size;
342 
343     size = get_du(dir);
344     if (size > 0) {
345         size = size / 1048576;
346     }
347     sprintf(tmpbuff, "%.2lf", size);
348     return tmpbuff;
349 }
350 */
351 /* quota_to_bytes: used to convert user entered quota (given in MB)
352                    back to bytes for vpasswd file
353    return value: 0 for success, 1 for failure
354 */
quota_to_bytes(char returnval[],char * quota)355 int quota_to_bytes(char returnval[], char *quota) {
356     double tmp;
357 
358     if (quota == NULL) { return 1; }
359     if ((tmp = atof(quota))) {
360         tmp *= 1048576;
361         sprintf(returnval, "%.0lf", tmp);
362         return 0;
363     } else {
364 	strcpy (returnval, "");
365 	return 1;
366     }
367 }
368 /* quota_to_megabytes: used to convert vpasswd representation of quota
369                        to number of megabytes.
370    return value: 0 for success, 1 for failure
371 */
quota_to_megabytes(char * returnval,char * quota)372 int quota_to_megabytes(char *returnval, char *quota) {
373     double tmp;
374     int i;
375 
376     if (quota == NULL) { return 1; }
377     i = strlen(quota);
378     if ((quota[i-1] == 'M') || (quota[i-1] == 'm')) {
379         tmp = atol(quota);  /* already in megabytes */
380     } else if ((quota[i-1] == 'K') || (quota[i-1] == 'k')) {
381 	tmp = atol(quota) * 1024;  /* convert kilobytes to megabytes */
382     } else if ((tmp = atol(quota))) {
383         tmp /= 1048576.0;
384     } else {
385 	strcpy (returnval, "");
386 	return 1;
387     }
388     sprintf(returnval, "%.2lf", tmp);
389     return 0;
390 }
391 
print_user_index(char * action,int colspan,char * user,char * dom,time_t mytime)392 void print_user_index (char *action, int colspan, char *user, char *dom, time_t mytime)
393 {
394 #ifdef USER_INDEX
395   int k;
396 
397   printf ("<tr bgcolor=%s>", get_color_text("000"));
398   printf ("<td colspan=%d align=\"center\">", colspan);
399   printf ("<hr>");
400   printf ("<b>%s</b> &nbsp; ", html_text[133]);
401   for (k = 0; k < 10; k++) {
402 	printh ("<a href=\"%s&searchuser=%d\">%d</a>\n", cgiurl(action), k, k);
403   }
404   for (k = 'a'; k <= 'z'; k++) {
405 	printh ("<a href=\"%s&searchuser=%c\">%c</a>\n", cgiurl(action), k, k);
406   }
407   printf ("</td>");
408   printf ("</tr>\n");
409 
410   printf ("<tr bgcolor=%s>", get_color_text("000"));
411   printf ("<td colspan=%d>", colspan);
412   printf ("<table border=0 cellpadding=3 cellspacing=0 width=\"100%%\"><tr><td align=\"center\"><br>");
413   printf ("<form method=\"get\" action=\"%s/com/%s\">", CGIPATH, action);
414   printh ("<input type=\"hidden\" name=\"user\" value=\"%H\">", user);
415   printh ("<input type=\"hidden\" name=\"dom\" value=\"%H\">", dom);
416   printf ("<input type=\"hidden\" name=\"time\" value=\"%u\">", (unsigned int) mytime);
417   printh ("<input type=\"text\" name=\"searchuser\" value=\"%H\">&nbsp;", SearchUser);
418   printf ("<input type=\"submit\" value=\"%s\">", html_text[204]);
419   printf ("</form>");
420   printf ("</td></tr></table>");
421   printf ("<hr>");
422   printf ("</td></tr>\n");
423 
424 #endif
425 }
426 
cgiurl(char * action)427 char *cgiurl (char *action)
428 {
429   static char url[256];
430 
431   snprinth (url, sizeof(url), "%s/com/%s?user=%C&dom=%C&time=%d",
432     CGIPATH, action, Username, Domain, Mytime);
433 
434   return url;
435 }
436 
437 /*
438  * Brian Kolaci
439  * updated function that doesn't require fts_*
440  */
441 /* bk - use maildir++ quotas now
442 off_t get_du(const char *dir_name)
443 {
444   DIR *dirp;
445   struct dirent *dp;
446   struct stat statbuf;
447   off_t file_size = 0;
448   char *tmpstr;
449 
450   if (dir_name == NULL)
451     return 0;
452 
453   if (chdir(dir_name) == -1)
454     return 0;
455 
456   if ((dirp = opendir(".")) == NULL)
457     return 0;
458 
459   while ((dp=readdir(dirp)) != NULL) {
460     if (!strcmp(dp->d_name, "..") || !strcmp(dp->d_name, "."))
461       continue;
462     if ((tmpstr=strstr(dp->d_name, ",S=")) != NULL) {
463       file_size += atol(tmpstr+3);
464     } else if (stat(dp->d_name,&statbuf)==0 && (statbuf.st_mode & S_IFDIR) ) {
465       file_size += get_du(dp->d_name);
466     }
467   }
468   closedir(dirp);
469   if (dir_name != NULL && strcmp(dir_name, ".." ) && strcmp(dir_name, "." ))
470     chdir("..");
471   return(file_size);
472 }
473 */
474