#pragma module SPOP3_VMSMAIL "SPOP3_VMSMAIL-1-F" #define __MODULE__ "SPOP3_VMSMAIL" /* **++ ** FACILITY: StarLet POP3 Server for OpenVMS ** ** MODULE DESCRIPTION: ** ** This module contains a routine set which covers an access to VMS MAIL. ** ** AUTHORS: ** ** Ruslan R. Laishev ** ** CREATION DATE: 30-JUL-2005 ** ** ** MODIFICATION HISTORY: ** 25-AUG-2005 RRL Added additional error condition handling into vmail_get_msg() ** Fixed logic bug in message expiration processing. ** 26-AUG-2005 RRL Added informational messages into vmail_init_ctx/vmail_shut_ctx. ** 30-AUG-2005 RRL Fixed problem with reseting of new mail count. ** 1-SEP-2005 RRL Disabled temporary PURGE/RECLAIM of MAIL.MAI, only purging WASTEBACKET, ** added pr_threshold global variable; ** added controling of access to a user's mailbox with LOCK. ** 3-SEP-2005 RRL Fixed MAIL$_INVITMLEN (8290682) in the vmail_get_msg(). ** 6-SEP-2005 RRL Fixed PURGE/RECLAIM problem. ** 25-JAN-2006 RRL Added mutex to ordering access to MAIL$ routines. ** 31-MAY-2006 RRL Added transformation of DECnet IV mail address to pseudo-Internet ** 4-NOV-2006 RRL Some changes in the handler(); ** 24-JAN-2007 RRL Temporarly removed locking an access to VMS Mail box. ** 8-OCT-2007 RRL Disabled signaling by process crashing CONV$RECLAIM. ** 24-OCT-2007 RRL Disabled user's condition handler, look to be good. ** 30-OCT-2007 RRL Enabled condition handler. ** 19-NOV-2007 RRL Fixed a bug in the condition handler. ** 27-NOV-2007 RRL Added an arbitrage of access to the mail$'s context in the vmail_shut_ctx(). ** 28-NOV-2007 RRL Some code cleanuping from unused & has been commented stuff. ** 28-FEB-2008 RRL Fixed set of FAB$M_NQL. ** ** [@tbs@]... **-- */ /* ** ** INCLUDE FILES ** */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #define __NEW_STARLET 1 #include #include "spop3def.h" #include "spop3_msg.h" #define INIT_SDESC(dsc, len, ptr) {(dsc).dsc$b_dtype = DSC$K_DTYPE_T;\ (dsc).dsc$b_class = DSC$K_CLASS_S; (dsc).dsc$w_length = (short) (len);\ (dsc).dsc$a_pointer = (ptr);} #define min(x,y) ((x > y)?y:x) #define max(x,y) ((x < y)?y:x) const ile3 nullist [] = {{0,MAIL$_NOSIGNAL,0,0},{0,0,0,0}}; extern unsigned char spop3_folder[]; extern int debug_flag, pr_threshold, spop3_new2mail; #define DEBUG if(debug_flag)printf("%-24.24s:%-08.0u ",__MODULE__,__LINE__);if(debug_flag)printf int spop3__log (); /* ** A mutex to controlling ordered access to MAIL$ routines */ pthread_mutex_t mail_mtx = PTHREAD_MUTEX_INITIALIZER; static int spop3_putmsg ( struct dsc$descriptor *msg, POP3CTX *ctx ) { int status,argl[5] = {0,0,0,0}; char buf[2048]; struct dsc$descriptor buf_dsc,fao_dsc; const char msg_pref[] = {"!%D-!AS"}, msg_pref_ctx[2][22] = {{"!%D-[!2ZB !AC/!AC]!AS"}, {"!%D-{!2ZB !AC/!AC}!AS"}}; INIT_SDESC(buf_dsc,sizeof(buf),buf); if ( !ctx ) { INIT_SDESC(fao_dsc,sizeof(msg_pref)-1,msg_pref); argl[1] = msg; } else { INIT_SDESC(fao_dsc,sizeof(msg_pref_ctx[0])-1,&msg_pref_ctx[ctx->pop3ctx$v_tls]); argl[1] = ctx->pop3ctx$b_idx; argl[2] = &ctx->pop3ctx$b_alen; argl[3] = &ctx->pop3ctx$b_ulen; argl[4] = msg; } if ( !(1 & (status = sys$faol(&fao_dsc,&buf_dsc.dsc$w_length,&buf_dsc,argl))) ) lib$signal(status); lib$put_output(&buf_dsc); return SS$_ABORT; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Initalize Virtual Memory ZONE. ** ** FORMAL PARAMETERS: ** ** None. ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ $DESCRIPTOR(VMZoneName_MHDR,"Mail Headers"); int VMZoneId_MHDR; int vmail_init (void) { int status,VMZoneBlockSz,VMZoneSz; const int VMZoneAlg = LIB$K_VM_FIXED, VMZoneFlags = LIB$M_VM_EXTEND_AREA | LIB$M_VM_GET_FILL0; /* ** Initialize VM zone for 128 mail headers by default */ VMZoneBlockSz = sizeof (MHDR); VMZoneSz = (VMZoneBlockSz * 128)/512; if ( !(1 & (status = lib$create_vm_zone(&VMZoneId_MHDR,&VMZoneAlg, &VMZoneBlockSz,&VMZoneFlags,0, &VMZoneSz,0,0,0,0,&VMZoneName_MHDR,0,0))) ) lib$signal(status); return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Initialize VMS MAIL contexts. Move all messages from NEWMAIL to MAIL folder, ** form a mail list by reading from MAIL folder. ** ** FORMAL PARAMETERS: ** ** ctx: SPOP3 context area ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int vmail_init_ctx ( POP3CTX *ctx ) { int status,st; unsigned userctx = 0,mailfile = 0,count = 0, newcount = 0; unsigned short retlen = 0; /* ** Get an user HOME Directory from the VMSMail profile datafile */ { ile3 in_lst[] = { {ctx->pop3ctx$b_ulen, MAIL$_USER_USERNAME,&ctx->pop3ctx$t_uname, 0}, {0,MAIL$_NOSIGNAL,0,0}, {0,0,0,0}}, in_lst2[] = { {ctx->pop3ctx$b_ulen, MAIL$_USER_USERNAME,&ctx->pop3ctx$t_uname, 0}, {sizeof(retlen), MAIL$_USER_SET_NEW_MESSAGES,&retlen, 0}, {0,MAIL$_NOSIGNAL,0,0}, {0,0,0,0}}, out_lst[] = { {255, MAIL$_USER_FULL_DIRECTORY, &ctx->pop3ctx$t_maildir[1], &retlen}, {0,0,0,0}}; /* ** Get an USER's information from the VMSMAIL_PROFILE.DAT file: ** MAIL' home directory; ** Reset "NEW MAIL COUNT" to zero; */ pthread_mutex_lock(&mail_mtx); if ( 1 & (status = mail$user_begin(&userctx,&nullist,&nullist)) ) { status = mail$user_get_info(&userctx,&in_lst,&out_lst); ctx->pop3ctx$t_maildir[0] = (unsigned char) retlen; retlen = 0; if ( !(1 & (st = mail$user_set_info(&userctx,&in_lst2,&nullist))) ) {int msgvec[] = {1,st}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} if ( !(1 & (st = mail$user_end (&userctx,&nullist,&nullist))) ) {int msgvec[] = {1,st}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} } pthread_mutex_unlock(&mail_mtx); if ( !(1 & status) ) return status; } /* ** Open a MAIL.MAI in the user's home directory, ** create a mailfile context */ { ile3 in_lst[] = { {ctx->pop3ctx$t_maildir[0], MAIL$_MAILFILE_NAME,&ctx->pop3ctx$t_maildir[1], 0}, {0,MAIL$_NOSIGNAL,0,0}, {0,0,0,0}}; pthread_mutex_lock(&mail_mtx); if ( (1 & (status = mail$mailfile_begin (&mailfile,&nullist,&nullist))) ) if ( !(1 & (status = mail$mailfile_open (&mailfile,&in_lst,&nullist))) ) { if ( !(1 & (st = mail$mailfile_close (&mailfile,&nullist,&nullist))) ) {int msgvec[] = {1,st}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} if ( !(1 & (st = mail$mailfile_end (&mailfile,&nullist,&nullist))) ) {int msgvec[] = {1,st}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} } pthread_mutex_unlock(&mail_mtx); if ( !(1 & status) ) { int msgvec[] = {1,status}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx); return status; } ctx->pop3ctx$l_mfile = mailfile; } /* ** Create a message context */ { ile3 in_lst[] = { {sizeof(ctx->pop3ctx$l_mfile), MAIL$_MESSAGE_FILE_CTX,&ctx->pop3ctx$l_mfile,0}, {0,MAIL$_NOSIGNAL,0,0}, {0,0,0,0}}; pthread_mutex_lock(&mail_mtx); if ( !(1 & (status = mail$message_begin (&ctx->pop3ctx$l_msgctx,&in_lst,&nullist))) ) { int msgvec[] = {1,status}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx); pthread_mutex_unlock(&mail_mtx); return status; } pthread_mutex_unlock(&mail_mtx); } /* ** Open NEWMAIL folder and move all mails to the MAIL folder */ if ( spop3_new2mail ) { unsigned messid; ile3 in_lst[] = { {7, MAIL$_MESSAGE_FOLDER, "NEWMAIL", 0}, {0,MAIL$_NOSIGNAL,0,0},{0,0,0,0}}, out_lst[] = { {4, MAIL$_MESSAGE_SELECTED,&count, 0}, {0,0,0,0}}, in_lst2[] = { {0, MAIL$_MESSAGE_NEXT, 0, 0}, {0,MAIL$_NOSIGNAL,0,0},{0,0,0,0}}, out_lst2[] = { {sizeof(messid),MAIL$_MESSAGE_CURRENT_ID ,&messid,0}, {0,MAIL$_NOSIGNAL,0,0},{0,0,0,0}}, in_lst3[] = { {sizeof(messid),MAIL$_MESSAGE_ID,&messid,0}, {4,MAIL$_MESSAGE_FOLDER, "MAIL", 0}, {0,MAIL$_MESSAGE_DELETE,0,0}, {0,MAIL$_NOSIGNAL,0,0 },{0,0,0,0}}; if ( 1 & (status = mail$message_select(&ctx->pop3ctx$l_msgctx,&in_lst,&out_lst)) ) { /* ** Move messages in loop */ for (int i = 0; i < count;i++ ) { if ( 1 & (status = mail$message_info(&ctx->pop3ctx$l_msgctx,&in_lst2,&out_lst2)) ) if ( 1 & (status = mail$message_copy(&ctx->pop3ctx$l_msgctx,&in_lst3,&nullist)) ) newcount++; } } } /* if ( spop3_new2mail ) */ if ( !(1 & (status = mail$message_end (&ctx->pop3ctx$l_msgctx,&nullist,&nullist))) ) { int msgvec[] = {1,status}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx); return status; } /* ** Recreating message context */ { ile3 in_lst[] = { {sizeof(ctx->pop3ctx$l_mfile), MAIL$_MESSAGE_FILE_CTX,&ctx->pop3ctx$l_mfile,0}, {0,MAIL$_NOSIGNAL,0,0},{0,0,0,0}}; pthread_mutex_lock(&mail_mtx); if ( !(1 & (status = mail$message_begin (&ctx->pop3ctx$l_msgctx,&in_lst,&nullist))) ) { int msgvec[] = {1,status}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx); pthread_mutex_unlock(&mail_mtx); return status; } pthread_mutex_unlock(&mail_mtx); } /* ** Open the default work mail folder */ { ile3 in_lst[] = { {spop3_folder[0], MAIL$_MESSAGE_FOLDER, &spop3_folder[1], 0}, {0,MAIL$_NOSIGNAL,0,0},{0,0,0,0}}, out_lst[] = { {4, MAIL$_MESSAGE_SELECTED,&count, 0}, {0,0,0,0}}; if ( !(1 & (status = mail$message_select(&ctx->pop3ctx$l_msgctx,&in_lst,&out_lst))) ) return status; } /* ** Run over folder and get messages information ** filling mails header list */ { MHDR *cur = NULL,*prev = NULL; unsigned short fromlen = 0,tolen = 0,subjlen = 0,extlen = 0; ile3 in_lst[] = { {0, MAIL$_MESSAGE_NEXT, 0, 0}, {0, MAIL$_NOSIGNAL,0,0 },{0,0,0,0}}, out_lst[] = { {4, MAIL$_MESSAGE_CURRENT_ID, 0,0}, {8, MAIL$_MESSAGE_BINARY_DATE, 0,0}, {4, MAIL$_MESSAGE_SIZE, 0,0}, {2, MAIL$_MESSAGE_RETURN_FLAGS, 0,0}, {255, MAIL$_MESSAGE_FROM, 0,&fromlen}, {255, MAIL$_MESSAGE_TO, 0,&tolen}, {255, MAIL$_MESSAGE_SUBJECT, 0,&subjlen}, {255, MAIL$_MESSAGE_EXTID, 0,&extlen}, {0,0,0,0}}; for (int i = 1; i <= count;i++ ) { /* ** If no free VM just stop geting mails */ if ( !(1 & (status = lib$get_vm(&sizeof(MHDR),&cur,&VMZoneId_MHDR))) ) break; out_lst[0].ile3$ps_bufaddr = &cur->mhdr$l_messid; out_lst[1].ile3$ps_bufaddr = &cur->mhdr$l_date; out_lst[2].ile3$ps_bufaddr = &cur->mhdr$l_lines; out_lst[3].ile3$ps_bufaddr = &cur->mhdr$w_flags; out_lst[4].ile3$ps_bufaddr = &cur->mhdr$t_from; out_lst[5].ile3$ps_bufaddr = &cur->mhdr$t_to; out_lst[6].ile3$ps_bufaddr = &cur->mhdr$t_subj; out_lst[7].ile3$ps_bufaddr = &cur->mhdr$t_extid; if ( !(1 & (status = mail$message_info(&ctx->pop3ctx$l_msgctx,&in_lst,&out_lst))) ) { if ( !(1 & (status = lib$free_vm(&sizeof(MHDR),&cur,&VMZoneId_MHDR))) ) lib$signal(status); break; } cur->mhdr$b_fromlen = (unsigned char)fromlen; cur->mhdr$b_tolen = (unsigned char)tolen; cur->mhdr$b_subjlen = (unsigned char)subjlen; cur->mhdr$b_extlen = (unsigned char)extlen; /* ** Is this message was sent with DECNET or Internet ? */ if ( !strncasecmp(cur->mhdr$t_from,"MX%",3) || !strncasecmp(cur->mhdr$t_from,"SMTP%",5) || !strncasecmp(cur->mhdr$t_from,"IN%",3)) cur->mhdr$v_decnet = 0; else { /* ** Transfom DECnet FROM-address from NODE::USER to USER@NODE */ char node [32],user [32]; cur->mhdr$v_decnet = 1; /* ** Is this DECnet IV address ? */ if ( 2 == sscanf(cur->mhdr$t_from,"%32[^:\n]::%32[^ \n]",&node,user) ) cur->mhdr$b_fromlen = (unsigned char) sprintf(cur->mhdr$t_from,"%s@%s",user,node); } ctx->pop3ctx$l_mlistsz++; ctx->pop3ctx$l_mlines += cur->mhdr$l_lines; if ( !ctx->pop3ctx$a_mlist ) { ctx->pop3ctx$a_mlist = cur; ctx->pop3ctx$a_mlast = cur; } if ( prev ) prev->mhdr$a_next = cur; prev = cur; } } if ( !(1 & status) ) {int msgvec[] = {1,status}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} spop3__log(ctx,POP3_INIMAILCTX,ctx->pop3ctx$l_mlistsz,newcount); return status; } /* ** http://www.eight-cubed.com/examples.shtml ** http://www.eight-cubed.com/examples/framework.php?file=lib_establish.c ** ISUBS.LIS: %sbttl 'reclaim_handler' */ static unsigned handler ( struct chfdef1 * sigargs, struct chfdef2 * mechargs ) { $DESCRIPTOR(hnd_dsc,"Executing condition handler..."); lib$put_output(&hnd_dsc); if ( sigargs->chf$is_sig_name == SS$_UNWIND ) return SS$_CONTINUE; if ( sigargs->chf$is_sig_name == SS$_ACCVIO ) return SS$_RESIGNAL; /* sigargs->chf$is_sig_args -= 2; lib$callg(&sigargs->chf$is_sig_args,lib$signal); sigargs->chf$is_sig_args += 2; */ lib$sig_to_ret(sigargs,mechargs); return 0; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Close all MAIL related files, deleting mails marked by user for deletion, ** additionaly performs auto-deletion of mails older then 'expire' days, ** performs PURGE/RECLAIM action. ** ** FORMAL PARAMETERS: ** ** ctx: SPOP3 context area ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int vmail_shut_ctx ( POP3CTX *ctx ) { unsigned status = SS$_NORMAL, option = LIB$K_DELTA_DAYS, deleted = 0, delcount = 0, sentcount = 0;; unsigned __int64 expire_date = 0, curtime; MHDR *mp = ctx->pop3ctx$a_mlist,*cur; ile3 in_lst[] = { {4,MAIL$_MESSAGE_ID,0,0}, {0,MAIL$_NOSIGNAL,0,0},{0,0,0,0}}; if ( !ctx ) return SS$_NORMAL; /* ** Is there expire option ? */ if ( mp && ctx->pop3ctx$l_expire ) { /* ** Convert number of days to VMS DATE */ if ( 1 & (status = sys$gettim (&curtime)) ) if ( 1 & (status = lib$cvt_to_internal_time(&option,&ctx->pop3ctx$l_expire,&expire_date)) ) status = lib$sub_times(&curtime,&expire_date,&expire_date); if ( !(1 & status) ) { int msgvec[] = {1,status}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx); expire_date = 0; } } else expire_date = 0; /* ** Run over the message list, release memory, performs message deletion */ while ( mp ) { /* ** Is there expiration option ? */ if ( expire_date ) { if ( mp->mhdr$v_deleted |= (mp->mhdr$q_date < expire_date) ) spop3__log(ctx,POP3_EXPIRED,mp->mhdr$l_messid, &mp->mhdr$b_fromlen,&mp->mhdr$b_tolen, &mp->mhdr$b_subjlen,&mp->mhdr$q_date); } if ( mp->mhdr$v_deleted ) { in_lst[0].ile3$ps_bufaddr = &mp->mhdr$l_messid; if ( !(1 & (status = mail$message_delete(&ctx->pop3ctx$l_msgctx,&in_lst,&nullist))) ) {int msgvec[] = {1,status}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} spop3__log(ctx,POP3_MDELETE,mp->mhdr$l_messid,status); delcount++; } if ( mp->mhdr$v_sent ) sentcount++; cur = mp; mp = mp->mhdr$a_next; if ( !(1 & (status = lib$free_vm(&sizeof(MHDR),&cur,&VMZoneId_MHDR))) ) lib$signal(status); } /* ** Close message context */ pthread_mutex_lock(&mail_mtx); if ( ctx->pop3ctx$l_msgctx && !(1 & (status = mail$message_end (&ctx->pop3ctx$l_msgctx,&nullist,&nullist))) ) {int msgvec[] = {1,status}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} /* ** Establishing a condition handler especialy for CONV$RECLAIM routine */ lib$establish (&handler); /* ** Close MAIL.MAI file */ if ( ctx->pop3ctx$l_mfile ) { /* ** If there exist deleted messages - purge WASTEBACKET folder */ if ( delcount ) { ile3 out_lst[] = { {4,MAIL$_MAILFILE_DELETED_BYTES,&deleted,0}, {0,0,0,0}}; if ( !(1 & (status = mail$mailfile_purge_waste(&ctx->pop3ctx$l_mfile,&nullist,&out_lst))) ) {int msgvec[] = {1,status}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} } /* ** Close MAIL.MAI & deallocate MAILFILE context */ if ( !(1 & (status = mail$mailfile_close (&ctx->pop3ctx$l_mfile,&nullist,&nullist))) ) {int msgvec[] = {1,status}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} if ( !(1 & (status = mail$mailfile_end (&ctx->pop3ctx$l_mfile,&nullist,&nullist))) ) {int msgvec[] = {1,status}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} } pthread_mutex_unlock(&mail_mtx); spop3__log(ctx,POP3_SHUTMAILCTX,delcount,ctx->pop3ctx$l_mlistsz - delcount,sentcount,deleted); /* ** If the global PURGE/RECLAIM Threshold has been defined then ** check a needness to performs CONVERT/RECLAIM operation on the user's MAIL.MAI file */ if ( deleted && pr_threshold && (deleted > pr_threshold) ) { unsigned short mfns = 0; unsigned char mfna[512]; struct dsc$descriptor mfile; struct recl$statistics stat = {4,0,0,0,0}; mfns = sprintf(mfna,"%.*sMAIL.MAI",ctx->pop3ctx$t_maildir[0],&ctx->pop3ctx$t_maildir[1]); INIT_SDESC(mfile,mfns,mfna); /* ** Performs a calling CONV$RECLAIM routine */ sys$setast(1); if ( !(1 & (status = conv$reclaim(&mfile,&stat,NULL, NULL))) ) {int msgvec[] = {1,status}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} // spop3__log(ctx,POP3_RECLAIM,stat.recl$l_scan_count,stat.recl$l_data_count, // stat.recl$l_index_count,stat.recl$l_total_count,status); } return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Retrievs a body of the specified message. A first call must be with the ** argument set to non-zero all next calls should be with the eqaly zero. ** ** FORMAL PARAMETERS: ** ** ctx: SPOP3 context area ** messid: a message number ** start: a flag to positioning to begin of mail ** buf: a buffer to accept a next mail record ** buflen: a size of the buffer ** retlen: a returned actual data length in the buffer ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int vmail_get_msg ( POP3CTX *ctx, MHDR *mp, int start, char *buf, unsigned short buflen, unsigned short *retlen ) { int status,st,rtype = 0,mextidlen = 0; char mextid [ 512 ] ; ile3 in_lst[] = { {0,MAIL$_MESSAGE_CONTINUE,0,0}, {4,MAIL$_MESSAGE_ID,&mp->mhdr$l_messid,0}, {0,MAIL$_NOSIGNAL,0,0},{0,0,0,0}}, out_lst[] = { {min(255,buflen),MAIL$_MESSAGE_RECORD,buf,retlen}, {2, MAIL$_MESSAGE_RECORD_TYPE,&rtype,0}, {0,0,0,0}}; *retlen = 0; /* ** If this mail is not in external file read it with MAIL$ API routines */ if ( !(mp->mhdr$w_flags & MAIL$M_EXTMSG) || (mp->mhdr$w_flags & MAIL$M_EXTFNF) || !ctx->pop3ctx$t_maildir[0] ) { /* ** Extract only a message body */ do { if ( !(1 & (status = mail$message_get(&ctx->pop3ctx$l_msgctx,&in_lst[start == 1],&out_lst))) ) return status; start = 0; } while ( rtype != MAIL$_MESSAGE_TEXT ); return status; } /* ** The mail has been stored in external file, ** read it with RMS API routines */ if ( start ) { /* ** Construct a full path-name to the file */ mextidlen = sprintf(mextid,"%.*s%.*s",ctx->pop3ctx$t_maildir[0],&ctx->pop3ctx$t_maildir[1], mp->mhdr$b_extlen,mp->mhdr$t_extid); /* ** Open external file */ ctx->pop3ctx$r_mfab = cc$rms_fab; ctx->pop3ctx$r_fhc = cc$rms_xabfhc; ctx->pop3ctx$r_mfab.fab$l_xab = &ctx->pop3ctx$r_fhc; ctx->pop3ctx$r_mfab.fab$b_fac = FAB$M_GET; ctx->pop3ctx$r_mfab.fab$b_shr = FAB$M_SHRGET | FAB$M_NQL; ctx->pop3ctx$r_mfab.fab$v_sqo = 1; ctx->pop3ctx$r_mfab.fab$l_fna = mextid; ctx->pop3ctx$r_mfab.fab$b_fns = mextidlen; if ( !(1 & (status = sys$open(&ctx->pop3ctx$r_mfab))) ) { int msgvec[] = {2,status,ctx->pop3ctx$r_mfab.fab$l_stv}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx); return status; } ctx->pop3ctx$r_mrab = cc$rms_rab; ctx->pop3ctx$r_mrab.rab$l_fab = &ctx->pop3ctx$r_mfab; ctx->pop3ctx$r_mrab.rab$v_nlk = 1; ctx->pop3ctx$r_mrab.rab$v_rrl = 1; ctx->pop3ctx$r_mrab.rab$b_mbf = 4; ctx->pop3ctx$r_mrab.rab$b_mbc = 4; if ( !(1 & (status = sys$connect(&ctx->pop3ctx$r_mrab))) ) { int msgvec[] = {2,status,ctx->pop3ctx$r_mrab.rab$l_stv}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx); return status; } ctx->pop3ctx$r_mrab.rab$v_nlk = 1; ctx->pop3ctx$r_mrab.rab$v_rrl = 1; ctx->pop3ctx$r_mfab.fab$l_ctx = 1; /* ** Store real mail size in the context */ mp->mhdr$l_msz = ctx->pop3ctx$r_fhc.xab$l_ebk*512 + ctx->pop3ctx$r_fhc.xab$w_ffb; } /* ** Read a next record from the stream */ ctx->pop3ctx$r_mrab.rab$l_ubf = buf; ctx->pop3ctx$r_mrab.rab$w_usz = buflen; if ( !(1 & (status = sys$get(&ctx->pop3ctx$r_mrab))) ) { if ( status != RMS$_EOF ) {int msgvec[] = {2,status,ctx->pop3ctx$r_mrab.rab$l_stv}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} /* ** In case of any error or EOF close the file */ if ( !(1 & (st = sys$disconnect(&ctx->pop3ctx$r_mrab))) ) {int msgvec[] = {2,st,ctx->pop3ctx$r_mrab.rab$l_stv}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} if ( !(1 & (st = sys$close(&ctx->pop3ctx$r_mfab))) ) {int msgvec[] = {2,st,ctx->pop3ctx$r_mfab.fab$l_stv}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} ctx->pop3ctx$r_mfab.fab$l_ctx = 0; } *retlen = ctx->pop3ctx$r_mrab.rab$w_rsz; return (status == RMS$_EOF?MAIL$_NOMOREREC:status); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Close file if it was opened with RMS. ** ** FORMAL PARAMETERS: ** ** ctx: SPOP3 context area ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int vmail_msg_end ( POP3CTX *ctx, MHDR *mp ) { int st; if ( !(mp->mhdr$w_flags & MAIL$M_EXTMSG) || (mp->mhdr$w_flags & MAIL$M_EXTFNF) || !ctx->pop3ctx$t_maildir[0] || !ctx->pop3ctx$r_mfab.fab$l_ctx ) return SS$_NORMAL; ctx->pop3ctx$r_mfab.fab$l_ctx = 0; /* ** Just close external MAI$*.MAI file */ if ( !(1 & (st = sys$disconnect(&ctx->pop3ctx$r_mrab))) ) {int msgvec[] = {2,st,ctx->pop3ctx$r_mrab.rab$l_stv}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} if ( !(1 & (st = sys$close(&ctx->pop3ctx$r_mfab))) ) {int msgvec[] = {2,st,ctx->pop3ctx$r_mfab.fab$l_stv}; sys$putmsg(&msgvec,spop3_putmsg,0,ctx);} return SS$_NORMAL; } #if 0 /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Returns a diskquota information for user defined by given context. ** ** FORMAL PARAMETERS: ** ** ctx: VMAIL API context ** total: a returned disk quota in bytes ** free: a returned not used free space ** ** RETURN VALUE: ** ** VMS condition code ** **-- */ int vmail_get_dquota ( struct vmail_ctx *ctx, unsigned *total, unsigned *free ) { int status,chan = 0; iosb io_status; struct _dqf quota; struct fibdef1 quota_fib; struct simple__desc { int cnt; void *ptr; } qfun = {sizeof(struct fibdef1),"a_fib}, qpar = {sizeof(struct _dqf),"a}; struct dsc$descriptor dev_dsc; /* ** */ sysprv_on(); memset("a,0,sizeof(struct _dqf)); memset("a_fib,0,sizeof(struct fibdef1)); INIT_SDESC(dev_dsc,ctx->fspec[0],&ctx->fspec[1]); quota.dqf$l_uic = ctx->uic; quota_fib.fib$w_cntrlfunc= FIB$C_EXA_QUOTA; quota_fib.fib$l_cntrlval = 0; if ( 1 & (status = sys$assign(&dev_dsc,&chan,0,0,0)) ) { status = sys$qiow(EFN$C_ENF,chan,IO$_ACPCONTROL,&io_status,0,0,&qfun,&qpar,0,&qpar,0,0); sys$dassgn(chan); } *total = 512*quota.dqf$l_permquota; *free = 512*(quota.dqf$l_permquota-quota.dqf$l_usage); return sysprv_off(!(1 & status)?status:io_status.iosb$w_status); } #endif