/* =========================================================================== = = = (C) Copyright 1991 The Trustees of Indiana University = = = = Permission to use, copy, modify, and distribute this program for = = non-commercial use and without fee is hereby granted, provided that = = this copyright and permission notice appear on all copies and = = supporting documentation, the name of Indiana University not be used = = in advertising or publicity pertaining to distribution of the program = = without specific prior permission, and notice be given in supporting = = documentation that copying and distribution is by permission of = = Indiana University. = = = = Indiana University makes no representations about the suitability of = = this software for any purpose. It is provided "as is" without express = = or implied warranty. = = = =========================================================================== = = = File: = = IUPOP3_VMS.C = = = = Synopsis: = = A collection of VMS system services and callable mail functions = = for the VMS IUPOP3 server. = = = = Authors: = = Jacob Levanon & Larry Hughes = = Indiana University = = University Computing Services, Network Applications = = = = Credits: = = This software is based on the Post Office Protocol version 3, = = as implemented by the University of California at Berkeley. = = = =========================================================================== */ /* ======================================================================== */ /* Includes */ /* ======================================================================== */ #include #include #include #include #include #include #include #include "iupop3_general.h" #include "iupop3_global.h" #include "iupop3_vms.h" /* ======================================================================== */ /* Prototypes */ /* ======================================================================== */ char *date_vms2unix(); float get_cpu(); int mail_close_file_context(); int mail_close_message_context(); int mail_close_user_context(); int mail_delete_message(); int mail_folder_select(); int mail_message_bytes(); char *mail_message_from(); int mail_message_lines(); int mail_message_new_count(); int mail_message_move(); int mail_open_file_context(); int mail_open_message_context(); int mail_open_user_context(); int mail_purge_waste(); int mail_retrieve_messages(); int mail_user_info(); void pop_log(); void system_log(); int user_exists(); char *vms_message(); /* ======================================================================== */ /* Date - VMS to Unix Format */ /* ======================================================================== */ char *date_vms2unix(char *vmsdate) { int year, month, day, saveyear, dayofweek; long julian, j1, j2, j3; char *daynames[] = { "Sun", "Mon", "Tues", "Wed", "Thu", "Fri", "Sat" }; char time[9]; char monthname[4]; static char buffer[32]; memcpy(buffer,vmsdate+7,4); buffer[4] = '\0'; saveyear = atoi(buffer); year = saveyear; memcpy(monthname,vmsdate+3,3); monthname[3] = '\0'; switch (monthname[0]) { case 'J': if (monthname[1] == 'A') month = 1; else if (monthname[2] == 'N') month = 6; else month = 7; break; case 'F': month = 2; break; case 'M': if (monthname[2] == 'R') month = 3; else month = 5; break; case 'A': if (monthname[1] == 'P') month = 4; else month = 8; break; case 'S': month = 9; break; case 'O': month = 10; break; case 'N': month = 11; break; default: month = 12; break; } monthname[1] = tolower(monthname[1]); monthname[2] = tolower(monthname[2]); memcpy(buffer,vmsdate,2); buffer[2] = '\0'; day = atoi(buffer); memcpy(time,vmsdate+12,8); time[8] = '\0'; if (year < 1584) buffer[0] = '\0'; else { if (month > 2) month -= 3; else { month += 9; year--; } j1 = 146097 * (year / 100) / 4; j2 = 1461L * (year % 100) / 4; j3 = (153L * month + 2) / 5 + day + 1721119; julian = j1 + j2 + j3; dayofweek = (int)(++julian % 7); sprintf(buffer,"%-3s, %02d %-3s %02d %-8s", daynames[dayofweek], day, monthname, (saveyear-1900), time); } return(buffer); } /* ======================================================================== */ /* Get CPU Utilization */ /* ======================================================================== */ float get_cpu() { int status; int cpu; int length; static int pid = 0; itemopen(outlist_ptr,outlist); itemadd(outlist_ptr,sizeof(cpu),JPI$_CPUTIM,&cpu,&length); itemclose(outlist_ptr); status = sys$getjpiw(0,&pid,0,outlist,0,0,0); if (vms_error(status)) { system_log("sys$getjpiw: %s",vms_message(status),0); cpu = 0; } return(((float)cpu) / (100.0)); } /* ======================================================================== */ /* Mail Close File Context */ /* ======================================================================== */ int mail_close_file_context(POP *p) { int status = SS$_NORMAL; if (p->file_context) { status = mail$mailfile_close(&p->file_context,nullist,nullist); if (vms_error(status)) pop_log(p,"mail$mailfile_close: %s",vms_message(status),0); status = mail$mailfile_end(&p->file_context,nullist,nullist); if (vms_error(status)) pop_log(p,"mail$mailfile_end: %s",vms_message(status),0); } return(status); } /* ======================================================================== */ /* Mail Close Message Context */ /* ======================================================================== */ int mail_close_message_context(POP *p) { int status = SS$_NORMAL; if (p->message_context) { status = mail$message_end(&p->message_context,nullist,nullist); if (vms_error(status)) pop_log(p,"mail$message_end: %s",vms_message(status),0); } return(status); } /* ======================================================================== */ /* Mail Close User Context */ /* ======================================================================== */ int mail_close_user_context(POP *p) { int status = SS$_NORMAL; if (p->user_context) { status = mail$user_end(&p->user_context,nullist,nullist); if (vms_error(status)) pop_log(p,"mail$user_end: %s",vms_message(status),0); } return(status); } /* ======================================================================== */ /* Mail Delete Message */ /* ======================================================================== */ int mail_delete_message(POP *p,int *message_id) { int status = SS$_NORMAL; if (!p->newmail_selected) status = mail_folder_select(p,newmail_folder); if (!vms_error(status)) { itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,sizeof(message_id),MAIL$_MESSAGE_ID,message_id,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); status = mail$message_delete(&p->message_context,inlist,nullist); if (vms_error(status)) pop_log(p,"mail$message_delete: %s",vms_message(status),0); } return(status); } /* ======================================================================== */ /* Mail Folder Select */ /* ======================================================================== */ int mail_folder_select(POP *p,char *folder_name) { #define MAX_MESSAGES 20 /* limit per connection per client */ int length; int messages = 0; int status; p->msg_count = 0; itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,strlen(folder_name),MAIL$_MESSAGE_FOLDER,folder_name,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); itemopen(outlist_ptr,outlist); itemadd(outlist_ptr,sizeof(messages),MAIL$_MESSAGE_SELECTED, &messages,&length); itemadd(outlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(outlist_ptr); status = mail$message_select(&p->message_context,inlist,outlist); if (vms_error(status)) { p->msg_count = 0; if (status == MAIL$_NOTEXIST) status = SS$_NORMAL; else pop_log(p,"mail$message_select: %s",vms_message(status),0); } else { p->msg_count = min(messages,MAX_MESSAGES); p->newmail_selected = TRUE; p->msgs_deleted = 0; } return(status); } /* ======================================================================== */ /* Mail Message Bytes */ /* ======================================================================== */ int mail_message_bytes(POP *p,int *message_id,unsigned int *bytes) { int length = 0, size; int lines = 0; int i, status; char external_id[256]; char path[256]; char buffer[256]; stat_t statbuf; Message *mp; int tmp, is_external=0; char errmsg1[] = "An error has been detected in this VMS mail file !!!"; char errmsg2[] = "It seems that the body of the message is missing on the VMS host"; char errmsg3[] = "Use the return address to contact the original sender..."; *bytes = 0; mp = &p->mptr[*message_id-1]; itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,sizeof(message_id),MAIL$_MESSAGE_ID,message_id,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); itemopen(outlist_ptr,outlist); itemadd(outlist_ptr,sizeof(external_id)-1,MAIL$_MESSAGE_EXTID,external_id, &length); itemadd(outlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(outlist_ptr); status = mail$message_info(&p->message_context,inlist,outlist); if (vms_error(status)) { pop_log(p,"mail$message_info: %s",vms_message(status),0); return(POP_FAILURE); } external_id[length] = '\0'; is_external = length; if (is_external > 0) { /* Mail file is external to MAIL.MAI */ sprintf(path,"%s%s",p->mail_directory,external_id); statbuf.st_size = 0; if (stat(path,&statbuf) < 0) /* problems with external file */ { pop_log(p,"stat failed",0); if ((tmp = creat(path ,0,"rat=cr","rfm=var","shr=nil")) < 0) pop_log(p,"creat failed",0); else { write(tmp, errmsg1, sizeof(errmsg1)); write(tmp, errmsg2, sizeof(errmsg2)); write(tmp, errmsg3, sizeof(errmsg3)); close(tmp); mp->lines = 4; /* adjust lines to report */ } } } itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,sizeof(message_id),MAIL$_MESSAGE_ID,message_id,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); status = mail$message_get(&p->message_context,inlist,outlist); if (vms_error(status)) pop_log(p,"mail$message_get: %s",vms_message(status),0); else { /* get the size of all header lines */ status = SS$_NORMAL; itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,0,MAIL$_MESSAGE_CONTINUE,0,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); itemopen(outlist_ptr,outlist); itemadd(outlist_ptr,sizeof(buffer)-1,MAIL$_MESSAGE_RECORD,buffer,&length); itemadd(outlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(outlist_ptr); status = SS$_NORMAL; for (i=1; i <=4; i++) { status = mail$message_get(&p->message_context,inlist,outlist); if (vms_error(status)) { pop_log(p,"mail$message_get in headers loop: %s", vms_message(status),0); return(POP_FAILURE); } buffer[length] = '\0'; *bytes += length; } } if (is_external > 0) { sprintf(path,"%s%s",p->mail_directory,external_id); statbuf.st_size = 0; if (stat(path,&statbuf) < 0) /* possible problems in external file */ pop_log(p,"stat failed",0); else *bytes = *bytes + statbuf.st_size; } /* Add bytes for "Date:" line */ if (*bytes > 0) *bytes += strlen("Date: DAY, DD MMM YY HH:MM:SS"); return(status); } /* ======================================================================== */ /* Mail Message From */ /* ======================================================================== */ char *mail_message_from(POP *p,int *message_id) { int length = 0; int status; char from_line[256]; if (!p->newmail_selected) status = mail_folder_select(p,newmail_folder); itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,sizeof(message_id),MAIL$_MESSAGE_ID,message_id,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); itemopen(outlist_ptr,outlist); itemadd(outlist_ptr,sizeof(from_line)-1,MAIL$_MESSAGE_FROM,from_line, &length); itemadd(outlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(outlist_ptr); status = mail$message_info(&p->message_context,inlist,outlist); from_line[length] = '\0'; if (vms_error(status)) { pop_log(p,"mail$message_info: %s",vms_message(status),0); return(NULL); } else return(&from_line); } /* ======================================================================== */ /* Mail Message Lines */ /* ======================================================================== */ int mail_message_lines(POP *p,int *message_id) { int length = 0; int status; int size = 0; itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,sizeof(message_id),MAIL$_MESSAGE_ID,message_id,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); itemopen(outlist_ptr,outlist); itemadd(outlist_ptr,sizeof(size),MAIL$_MESSAGE_SIZE,&size,&length); itemadd(outlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(outlist_ptr); status = mail$message_info(&p->message_context,inlist,outlist); if (vms_error(status)) { pop_log(p,"mail$message_info: %s",vms_message(status),0); return(-1); } return(size); } /* ======================================================================== */ /* Mail Open File Context */ /* ======================================================================== */ int mail_open_file_context(POP *p) { int status; pop_log(p,"opening %s",p->mail_file,0); status = mail$mailfile_begin(&p->file_context,nullist,nullist); if (vms_error(status)) pop_log(p,"mail$mailfile_begin: %s",vms_message(status),0); else { itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,strlen(p->mail_file),MAIL$_MAILFILE_NAME, &p->mail_file,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); status = mail$mailfile_open(&p->file_context,inlist,nullist); if (vms_error(status)) pop_log(p,"mail$mailfile_open: %s",vms_message(status),0); } if (vms_error(status)) p->file_context = NO_CONTEXT; return(status); } /* ======================================================================== */ /* Mail Open Message Context */ /* ======================================================================== */ int mail_open_message_context(POP *p) { int status; itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,sizeof(p->file_context),MAIL$_MESSAGE_FILE_CTX, &p->file_context,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); status = mail$message_begin(&p->message_context,inlist,nullist); if (vms_error(status)) { pop_log(p,"mail$message_begin: %s",vms_message(status),0); p->message_context = NO_CONTEXT; } return(status); } /* ======================================================================== */ /* Mail Open User Context */ /* ======================================================================== */ int mail_open_user_context(POP *p) { int status; status = mail$user_begin(&p->user_context,nullist,nullist); if (vms_error(status)) { p->user_context = NO_CONTEXT; pop_log(p,"mail$user_begin: %s",vms_message(status),0); } return(status); } /* ======================================================================== */ /* Mail Retrieve Messages */ /* ======================================================================== */ int mail_retrieve_messages(POP *p,int message_id, int numlines) { #define MAXHEADERS 4 int status = SS$_NORMAL; int bytes; int length; int lines=0, headers=1; short int record_type; char buffer[256], hold_cc[256], hold_to[256], tmp[256], message_date[32]; char *pointer; if (!p->newmail_selected) status = mail_folder_select(p,newmail_folder); if (!vms_error(status)) { if ((message_id < 1) || (message_id > p->msg_count)) return (pop_msg (p,POP_FAILURE,"Message %d does not exist.",message_id,0)); else { retrieved_messages++; if (message_id > p->last_msg) p->last_msg = message_id; itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,sizeof(message_id),MAIL$_MESSAGE_ID,&message_id,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); itemopen(outlist_ptr,outlist); itemadd(outlist_ptr,sizeof(message_date),MAIL$_MESSAGE_DATE, message_date,&length); itemadd(outlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(outlist_ptr); status = mail$message_get(&p->message_context,inlist,outlist); if (vms_error(status)) { pop_log(p,"mail$message_get: %s",vms_message(status),0); return(POP_FAILURE); } else { pop_log(p,"headers follow",0); message_date[length] = '\0'; sprintf(buffer,"Date: %s",date_vms2unix(message_date)); pop_sendline(p, buffer); printf(" %s",buffer); itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,0,MAIL$_MESSAGE_CONTINUE,0,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); itemopen(outlist_ptr,outlist); itemadd(outlist_ptr,sizeof(buffer)-1,MAIL$_MESSAGE_RECORD,buffer, &length); itemadd(outlist_ptr,sizeof(record_type),MAIL$_MESSAGE_RECORD_TYPE, &record_type,0); itemadd(outlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(outlist_ptr); status = SS$_NORMAL; for (headers=1; headers<=MAXHEADERS && !vms_error(status); headers++) { status = mail$message_get(&p->message_context,inlist,outlist); if (vms_error(status)) { pop_log(p,"mail$message_get: %s",vms_message(status),0); return(POP_FAILURE); } else { buffer[length] = '\0'; while ((pointer = strchr(buffer,'\t')) != NULL) *pointer = ' '; switch (headers) { case FROM_LINE: printf(" %s\n",buffer); #ifdef PATCH_FROM_LINE patch_from_line(p,buffer); #endif pop_sendline(p, buffer); printf(" %s",buffer); break; case CC_LINE: strcpy(hold_cc, buffer); lower(&hold_cc[1]); break; case SUBJECT_LINE: sprintf(tmp,"Subject%s", &buffer[4]); p->newmail_size = p->newmail_size+3; pop_sendline(p, tmp); printf(" %s",tmp); pop_sendline(p, hold_to); printf(" %s",hold_to); pop_sendline(p, hold_cc); printf(" %s",hold_cc); break; case TO_LINE: strcpy(hold_to, buffer); lower(&hold_to[1]); break; } } } while (lines < numlines && !vms_error(status)) { status = mail$message_get(&p->message_context,inlist,outlist); if (vms_error(status)) { pop_log(p,"mail$message_get: %s",vms_message(status),0); return(POP_FAILURE); } else { buffer[length] = '\0'; lines++; pop_sendline(p, buffer); } } } } } else { pop_log(p,"retrieve_message context: %s",vms_message(status),0); return(POP_FAILURE); } return(POP_SUCCESS); } /* ======================================================================== */ /* Mail User Info */ /* ======================================================================== */ int mail_user_info(POP *p) { int status; int length = 0; char scratch[256]; itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,strlen(p->user),MAIL$_USER_USERNAME, &p->user,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); itemopen(outlist_ptr,outlist); itemadd(outlist_ptr,sizeof(scratch)-1,MAIL$_USER_FULL_DIRECTORY,scratch, &length); itemadd(outlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(outlist_ptr); status = mail$user_get_info(&p->user_context,inlist,outlist); scratch[length] = '\0'; if (vms_error(status)) pop_log(p,"mail$user_get_info: %s",vms_message(status),0); else { strcpy(p->mail_directory,scratch); strcpy(p->mail_file,scratch); strcat(p->mail_file,"MAIL.MAI"); } return(status); } /* ========================================================================= */ /* User Exists */ /* ========================================================================= */ int user_exists(char *username) { int status; int value = FALSE; int flags; char upcase_username[80]; struct dsc$descriptor_s username_desc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0}; strcpy(upcase_username,username); upper(upcase_username); itemopen(outlist_ptr,outlist); itemadd(outlist_ptr,sizeof(flags),UAI$_FLAGS,&flags,0); itemclose(outlist_ptr); username_desc.dsc$a_pointer = upcase_username; username_desc.dsc$w_length = strlen(upcase_username); status = sys$getuai(0,0,&username_desc,outlist,0,0,0); if (vms_error(status)) system_log("sys$getuai error for \"%s\": %s",username,vms_message(status),0); else { if (!(flags & UAI$M_NOMAIL)) value = TRUE; } return(value); } /* ========================================================================== */ /* VMS Message String */ /* ========================================================================== */ char *vms_message(unsigned int code) { static char message[256]; unsigned short length = 0; struct dsc$descriptor message_dx; memset(message,0,sizeof(message)); message_dx.dsc$w_length = sizeof(message); message_dx.dsc$a_pointer = &message; sys$getmsg(code,&length,&message_dx,0xf,0); message[length] = '\0'; return(&message); } /* ======================================================================== */ /* Mail Message Move */ /* ======================================================================== */ int mail_message_move(POP *p,int message_id) { int status = SS$_NORMAL; char mail_folder[] = "MAIL"; if (!p->newmail_selected) status = mail_folder_select(p, newmail_folder); if (vms_error(status)) return(POP_FAILURE); else { itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,sizeof(message_id),MAIL$_MESSAGE_ID,&message_id,0); itemadd(inlist_ptr,strlen(p->mail_file),MAIL$_MESSAGE_DEFAULT_NAME, &p->mail_file,0); itemadd(inlist_ptr,strlen(mail_folder),MAIL$_MESSAGE_FOLDER,mail_folder,0); itemadd(inlist_ptr,0,MAIL$_MESSAGE_DELETE,0,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); status = mail$message_copy(&p->message_context,inlist,nullist); if (vms_error(status)) { pop_log(p,"mail$message_copy: %s",vms_message(status),0); return(POP_FAILURE); } } return(POP_SUCCESS); } /* ======================================================================== */ /* Mail Mark Deleted */ /* ======================================================================== */ int mail_message_new_count(POP *p) { int status = SS$_NORMAL; itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,strlen(p->user),MAIL$_USER_USERNAME, &p->user,0); itemadd(inlist_ptr, sizeof(p->msg_count),MAIL$_USER_SET_NEW_MESSAGES, &p->msg_count,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); status = mail$user_set_info(&p->user_context,inlist,nullist); if (vms_error(status)) pop_log("mail$user_set_info: %s",vms_message(status),0); return(status); } /* ======================================================================== */ /* MailFile Purge Waste */ /* ======================================================================== */ int mail_purge_waste(POP *p) { int status = SS$_NORMAL; itemopen(inlist_ptr,inlist); itemadd(inlist_ptr,0,MAIL$_MAILFILE_RECLAIM,0,0); itemadd(inlist_ptr,0,MAIL$_NOSIGNAL,0,0); itemclose(inlist_ptr); status = mail$mailfile_purge_waste(&p->file_context,inlist,nullist); if (vms_error(status)) { pop_log(p,"mail$mailfile_purge_waste: %s",vms_message(status),0); return(POP_FAILURE); } return(POP_SUCCESS); }