#pragma module NNTP_DB "NNTP_DB-1-B" /* **++ ** FACILITY: NNTP Server for OpenVMS ** ** MODULE DESCRIPTION: ** ** A NNTP oriented database API. ** ** AUTHORS: ** ** Ruslan R. Laishev ** ** CREATION DATE: ??-???-1996 ** ** DESIGN ISSUES: ** ** {@tbs@} ** ** ** MODIFICATION HISTORY: ** ** 20-MAY-2002 RRL Added MsgDBdel_byId(). ** ** {@tbs@}... **-- */ /* ** ** INCLUDE FILES ** */ #include "nntp.h" /* ** ** DATABASE FILES NAMES ** */ char MsgDBname[] = "nntp$msg"; char GrpDBname[] = "nntp$grp"; char FeedSuckDBname[]= "nntp$feedsuck"; $DESCRIPTOR(msggrp_fao,"!AC !11ZL"); struct FAB Msgfab; struct XABKEY MsgGrp; struct XABKEY MsgId; char MsgGrp$_knm[] = "News Groups ID + # Article "; char MsgId$_knm[] = "Message ID "; /* */ struct FAB Grpfab; struct XABKEY GrpName; char GrpName$_knm[] = "News Groups ID "; /* */ struct FAB FeedSuckfab; struct RAB FeedSuckrab; struct XABKEY FeedSuckxab; char FeedSuck$_knm[] = " Host_IP ',' News Groups ID "; char DEFEXT [] = ".DB"; /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Opens a message database file. ** ** FORMAL PARAMETERS: ** ** None. ** ** RETURN VALUE: ** ** RMS status ** **-- */ int MsgDBopen (void) { int status; /* ** Set-up FAB$ */ Msgfab = cc$rms_fab; Msgfab.fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_UPD | FAB$M_DEL; Msgfab.fab$b_shr = FAB$M_SHRGET | FAB$M_SHRPUT | FAB$M_SHRUPD | FAB$M_SHRDEL; Msgfab.fab$l_fna = MsgDBname; Msgfab.fab$v_mse = 1; Msgfab.fab$b_fns = sizeof(MsgDBname)-1; Msgfab.fab$w_mrs = sizeof(MSGREC); Msgfab.fab$b_org = FAB$C_IDX; Msgfab.fab$b_rat = FAB$M_CR; Msgfab.fab$l_fop = FAB$M_CIF | FAB$M_CBT; Msgfab.fab$b_rfm = FAB$C_VAR; Msgfab.fab$l_dna = DEFEXT; Msgfab.fab$b_dns = sizeof(DEFEXT)-1; /* ** XABKEY$MsgGrp: comp.os.vms,vmsnet.test... + Article number */ MsgGrp = cc$rms_xabkey; MsgGrp.xab$b_ref = MSG$K_GID_REF; MsgGrp.xab$b_dtp = XAB$C_STG; MsgGrp.xab$b_flg = XAB$M_DUP; MsgGrp.xab$w_pos0= MSG$K_GID_POS; MsgGrp.xab$b_siz0= GRPID$_LEN; Msgfab.fab$l_xab = (char* ) &MsgGrp; /* ** XABKEY$MsgId: <4358asdfd@petrobank.spb.su>... */ MsgId = cc$rms_xabkey; MsgId.xab$b_ref = MSG$K_MID_REF; MsgId.xab$b_dtp = XAB$C_STG; MsgId.xab$b_flg = XAB$M_DUP; MsgId.xab$w_pos0= MSG$K_MID_POS; MsgId.xab$b_siz0= MSGID$_LEN; MsgGrp.xab$l_nxt = (char *) &MsgId; /* ** Open or Create file (if need) */ MsgGrp.xab$l_knm = MsgGrp$_knm; MsgId.xab$l_knm = MsgId$_knm; if ( !(1 & (status = sys$create (&Msgfab))) ) lib$signal(status,Msgfab.fab$l_stv); return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Opens a group database file. ** ** FORMAL PARAMETERS: ** ** None. ** ** RETURN VALUE: ** ** RMS status ** **-- */ int GrpDBopen (void) { int status; /* ** FAB$ */ Grpfab = cc$rms_fab; Grpfab.fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_UPD | FAB$M_DEL; Grpfab.fab$b_shr = FAB$M_SHRGET | FAB$M_SHRPUT | FAB$M_SHRUPD | FAB$M_SHRDEL; Grpfab.fab$l_fna = GrpDBname; Grpfab.fab$v_mse = 1; Grpfab.fab$b_fns = sizeof(GrpDBname)-1; Grpfab.fab$w_mrs = sizeof(GRPREC); Grpfab.fab$b_org = FAB$C_IDX; Grpfab.fab$b_rat = FAB$M_CR; Grpfab.fab$l_fop = FAB$M_CIF | FAB$M_CBT; Grpfab.fab$b_rfm = FAB$C_VAR; Grpfab.fab$l_dna = DEFEXT; Grpfab.fab$b_dns = sizeof(DEFEXT)-1; /* ** XABKEY$GrpName: comp.os.vms,vmsnet.test... */ GrpName = cc$rms_xabkey; GrpName.xab$b_ref = GrpName.xab$b_flg = 0; GrpName.xab$b_dtp = XAB$C_STG; GrpName.xab$w_pos0= GRP$K_NAME_POS; GrpName.xab$b_siz0= GRPNAME$_LEN; Grpfab.fab$l_xab = (char* ) &GrpName; /* ** Open or Create file (if need) */ GrpName.xab$l_knm = GrpName$_knm; if ( !(1 & (status = sys$create (&Grpfab))) ) lib$signal(status,Grpfab.fab$l_stv); return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Opens a special database file which keep an information about ** feeds and sucks. ** ** FORMAL PARAMETERS: ** ** None. ** ** RETURN VALUE: ** ** RMS status ** **-- */ int FeedSuckDBopen (void) { long status; /* ** FAB$ */ FeedSuckfab= cc$rms_fab; FeedSuckfab.fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_UPD | FAB$M_DEL; FeedSuckfab.fab$b_shr = FAB$M_SHRGET | FAB$M_SHRPUT | FAB$M_SHRUPD | FAB$M_SHRDEL; FeedSuckfab.fab$v_mse = 1; FeedSuckfab.fab$l_fna = FeedSuckDBname; FeedSuckfab.fab$b_fns = sizeof(FeedSuckDBname) - 1; FeedSuckfab.fab$w_mrs = sizeof(FSREC); FeedSuckfab.fab$b_org = FAB$C_IDX; FeedSuckfab.fab$b_rat = FAB$M_CR; FeedSuckfab.fab$l_fop = FAB$M_CIF | FAB$M_CBT; FeedSuckfab.fab$l_dna = DEFEXT; FeedSuckfab.fab$b_dns = sizeof(DEFEXT)-1; /* ** XABKEY$SuckName: Hash of MD5 ("194.220.60.71,comp.os.vms") */ FeedSuckxab = cc$rms_xabkey; FeedSuckxab.xab$b_ref = 0; FeedSuckxab.xab$b_dtp = XAB$C_STG; FeedSuckxab.xab$b_flg = 0; FeedSuckxab.xab$w_pos0= FS$K_FS_POS; FeedSuckxab.xab$b_siz0= FS$K_FS_LEN; FeedSuckfab.fab$l_xab = (char *) &FeedSuckxab; /* ** Open or Create file (if need) */ FeedSuckxab.xab$l_knm = FeedSuck$_knm; if ( !(1 & (status = sys$create (&FeedSuckfab))) ) lib$signal(status,FeedSuckfab.fab$l_stv); return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Connect a specified RAB to message database file. ** ** FORMAL PARAMETERS: ** ** rabp: a RAB structure ** ** RETURN VALUE: ** ** RMS status ** **-- */ int MsgDBopen_stream (struct RAB *rabp) { int status; *rabp = cc$rms_rab; rabp->rab$l_fab = &Msgfab; rabp->rab$b_rac = RAB$C_KEY; rabp->rab$v_wat = 1; /* Wait if record is currently locked, */ rabp->rab$b_tmo = 250; /* 250 second before return */ status = sys$connect (rabp); rabp->rab$v_nlk = 1; return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Connect a specified RAB to group database file. ** ** FORMAL PARAMETERS: ** ** rabp: a RAB structure ** ** RETURN VALUE: ** ** RMS status ** **-- */ int GrpDBopen_stream (struct RAB *rabp) { *rabp = cc$rms_rab; rabp->rab$l_fab = &Grpfab; rabp->rab$b_rac = RAB$C_KEY; rabp->rab$b_krf = 0; rabp->rab$v_wat = 1; /* Wait if record is currently locked */ rabp->rab$b_tmo = 250; /* 250 second before return */ rabp->rab$v_uif = 1; /* Update if record (primary key) exist */ return sys$connect (rabp); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Connect a specified RAB to feed&suck database file. ** ** FORMAL PARAMETERS: ** ** rabp: a RAB structure ** ** RETURN VALUE: ** ** RMS status ** **-- */ int FeedSuckDBopen_stream (struct RAB *rabp) { int status; *rabp = cc$rms_rab; rabp->rab$l_fab = &FeedSuckfab; rabp->rab$b_rac = RAB$C_KEY; rabp->rab$b_krf = 0; rabp->rab$v_uif = 1; status = sys$connect (rabp); rabp->rab$v_nlk = 1; return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Flush buffers, release all locked records and close stream. ** ** FORMAL PARAMETERS: ** ** rabp: a RAB structure ** ** RETURN VALUE: ** ** RMS status ** **-- */ int DBclose_stream (struct RAB *rabp) { int status; status = sys$flush(rabp); status = sys$free (rabp); return sys$disconnect(rabp); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Open all databases files. ** ** FORMAL PARAMETERS: ** ** None. ** ** RETURN VALUE: ** ** RMS status ** **-- */ int DBopen (void) { int status; if ( !(1 & (status = MsgDBopen())) ) lib$signal(status); if ( !(1 & (status = GrpDBopen())) ) lib$signal(status); if ( !(1 & (status = FeedSuckDBopen())) ) lib$signal(status); return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Close all databases files. ** ** FORMAL PARAMETERS: ** ** None. ** ** RETURN VALUE: ** ** SS$_NORMAL ** **-- */ int DBclose (void) { int status; if ( !(1 & (status = sys$close (&Msgfab))) ) lib$signal(status); if ( !(1 & (status = sys$close (&Grpfab))) ) lib$signal(status); if ( !(1 & (status = sys$close (&FeedSuckfab))) ) lib$signal(status); return SS$_NORMAL; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Performs a finding message by Message-Id w/o locking. ** ** FORMAL PARAMETERS: ** ** mrabp: a pointer to RAB structure ** msgid: a message id to looking for *** msgidlen: a length of the message id ** ** RETURN VALUE: ** ** RMS status ** **-- */ int MsgDBfind_byId ( struct RAB *mrabp, char *msgid, ushort msgidlen ) { int status; /* ** Set-up RAB's key part */ mrabp->rab$b_krf = MSG$K_MID_REF; mrabp->rab$b_rac = RAB$C_KEY; mrabp->rab$l_kbf = msgid; mrabp->rab$b_ksz = msgidlen; mrabp->rab$v_nlk = 1; return sys$find (mrabp); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Performs a finding and retriving a message by Message-Id w/o locking. ** ** FORMAL PARAMETERS: ** ** mrabp: a pointer to RAB structure ** msgid: a message id to looking for ** msgidlen: a length of the message id ** mrec: a pointer to retrieved message ** mreclen: a length of the message ** ** RETURN VALUE: ** ** RMS status ** **-- */ int MsgDBget_byId ( struct RAB *mrabp, char *msgid, ushort msgidlen, MSGREC *mrec, ushort *mreclen ) { int status; /* ** Setup a RAB to searching */ mrabp->rab$b_krf = MSG$K_MID_REF; mrabp->rab$b_rac = RAB$C_KEY; mrabp->rab$l_kbf = msgid; mrabp->rab$b_ksz = msgidlen; mrabp->rab$l_ubf = (char *) mrec; mrabp->rab$w_usz = sizeof(MSGREC); mrabp->rab$v_nlk = 1; /* ** Search and get message */ status = sys$get (mrabp); *mreclen= mrabp->rab$w_rsz - MSG$K_BODY_POS; return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Performs a retriving a message with given number in the given group w/o locking. ** ** FORMAL PARAMETERS: ** ** mrabp: a pointer to RAB structure ** grec: a pointer to group record ** msgidx: a message index ** mrec: a pointer to retrived message ** mreclen: a length of the message ** ** RETURN VALUE: ** ** RMS status ** **-- */ int MsgDBget_byNum ( struct RAB *mrabp, GRPREC *grec, ulong MsgIdx, MSGREC *mrec, ushort *mreclen ) { int status; struct dsc$descriptor_s key_dsc; /* ** Perfom GroupName + Number article's key generation */ INIT_SDESC(key_dsc,sizeof(mrec->msg$t_gid),mrec->msg$t_gid); if ( !(1 & (status = sys$fao(&msggrp_fao,&key_dsc.dsc$w_length,&key_dsc, &grec->grp$b_grplen,MsgIdx))) ) return status; mrabp->rab$b_krf = MSG$K_GID_REF; mrabp->rab$b_rac = RAB$C_KEY; mrabp->rab$l_kbf = key_dsc.dsc$a_pointer; mrabp->rab$b_ksz = key_dsc.dsc$w_length; mrabp->rab$l_ubf = (char *) mrec; mrabp->rab$w_usz = sizeof(MSGREC); mrabp->rab$v_nlk = 1; if ( !(1 & (status = sys$get (mrabp))) ) return status; /* ** Check for reference and get message body by Mess-ID */ if ( mrec->msg$t_mid[0] == '>' ) { mrec->msg$t_mid[0] = '<'; return MsgDBget_byId(mrabp,mrec->msg$t_mid,mrec->msg$w_midlen, mrec,mreclen); } *mreclen= mrabp->rab$w_rsz - MSG$K_BODY_POS; return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Performs a deleting a message with given number in the given group. ** ** FORMAL PARAMETERS: ** ** mrabp: a pointer to RAB structure ** grec: a pointer to group record ** msgidx: a message index ** mrec: a pointer to retrived message ** ** RETURN VALUE: ** ** RMS status ** **-- */ int MsgDBdel_byNum ( struct RAB *mrabp, GRPREC *grec, ulong MsgIdx, MSGREC *mrec ) { int status; struct dsc$descriptor_s key_dsc; /* ** Perfom GroupName + Number article's key generation */ INIT_SDESC(key_dsc,sizeof(mrec->msg$t_gid),mrec->msg$t_gid); if ( !(1 & (status = sys$fao(&msggrp_fao,&key_dsc.dsc$w_length,&key_dsc, &grec->grp$b_grplen,MsgIdx))) ) return status; mrabp->rab$b_krf = MSG$K_GID_REF; mrabp->rab$b_rac = RAB$C_KEY; mrabp->rab$l_kbf = key_dsc.dsc$a_pointer; mrabp->rab$b_ksz = key_dsc.dsc$w_length; mrabp->rab$v_nlk = 0; if ( 1 & (status = sys$find (mrabp)) ) status = sys$delete (mrabp); return status==RMS$_RNF?SS$_NORMAL:status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Performs a reading group record from group database file. ** ** FORMAL PARAMETERS: ** ** grabp: a pointer to RAB structure ** grec: a pointer to group record ** lockf: a flag to read with/without locking ** rewindf: a rewind flag ** racf: a record access code flag ** ** RETURN VALUE: ** ** RMS status ** **-- */ int GrpDBget ( struct RAB *grabp, GRPREC *grec, int lockf, int rewindf, int racf ) { int status; /* ** Setup a RAB */ grabp->rab$b_rac = (racf?RAB$C_SEQ:RAB$C_KEY); grabp->rab$l_kbf = grec->grp$t_grpname; grabp->rab$b_ksz = grec->grp$b_grplen; grabp->rab$l_ubf = (char *) grec; grabp->rab$w_usz = sizeof(GRPREC); grabp->rab$v_nlk = (lockf?0:1); /* ** Rewind if need */ if ( !rewindf && racf ) if ( !(1 & (status = sys$rewind (grabp))) ) return status; /* ** Retrieve a group record */ return sys$get (grabp); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Release all locked groups reecords in group database file. ** ** FORMAL PARAMETERS: ** ** grabp: a pointer to RAB structure ** ** RETURN VALUE: ** ** RMS status ** **-- */ int GrpDBfree (struct RAB *grabp) { return sys$free (grabp); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Performs a reading group record from group database file. ** ** FORMAL PARAMETERS: ** ** grabp: a pointer to RAB structure ** grec: a pointer to group record ** ** RETURN VALUE: ** ** RMS status ** **-- */ int GrpDBput ( struct RAB *grabp, GRPREC *grec ) { int status; grabp->rab$b_rac = RAB$C_KEY; grabp->rab$l_kbf = grec->grp$t_grpname; grabp->rab$b_ksz = grec->grp$b_grplen; grabp->rab$l_rbf = (char *) grec; grabp->rab$w_rsz = sizeof(GRPREC); status = sys$put (grabp); sys$free (grabp); if ( !(1 & status) ) lib$signal(status,grabp->rab$l_stv); return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Insert message into a given group, if message is take place but in othre group ** insert a mark to the message. ** ** FORMAL PARAMETERS: ** ** grabp: a pointer to RAB structure, group database ** mrabp: a pointer to RAB structure, message atabase ** grec: a pointer to current group ** Date: a timestamp ** mrec: a pointer to message record to insert into databases ** mreclen: a length of the message record ** ** RETURN VALUE: ** ** RMS status ** **-- */ int DBins ( struct RAB *grabp, struct RAB *mrabp, GRPREC *grec, time_t Date, MSGREC *mrec, ushort mreclen ) { int status,faostatus; struct dsc$descriptor_s out_dsc; /* ** Get group's information with LOCK */ grabp->rab$b_rac = RAB$C_KEY; grabp->rab$l_kbf = grec->grp$t_grpname; grabp->rab$b_ksz = grec->grp$b_grplen; grabp->rab$l_ubf = (char *) grec; grabp->rab$w_usz = sizeof(GRPREC); grabp->rab$v_nlk = 0; if ( !(1 & (status = sys$get (grabp))) ) { sys$free(grabp); return status; } /* ** Check allowing of a post operation */ if ( 'n' == grec->grp$b_post ) { sys$free(grabp); return SS$_ABORT; } /* ** Perform neccesary modification in the group record */ grec->grp$l_datecr = (grec->grp$l_datecr == 0?Date:grec->grp$l_datecr); grec->grp$l_first = (grec->grp$l_first == 0?1:grec->grp$l_first); grec->grp$l_last++; /* ** Check for presence of the article in the database */ mrabp->rab$b_krf = MSG$K_MID_REF; mrabp->rab$b_rac = RAB$C_KEY; mrabp->rab$l_kbf = mrec->msg$t_mid; mrabp->rab$b_ksz = mrec->msg$w_midlen; status = sys$find (mrabp); memset(mrec->msg$t_gid,0,sizeof(mrec->msg$t_gid)); INIT_SDESC(out_dsc,sizeof(mrec->msg$t_gid),mrec->msg$t_gid); faostatus = sys$fao(&msggrp_fao,&mrec->msg$w_gidlen,&out_dsc, &grec->grp$b_grplen,grec->grp$l_last); if ( !(faostatus & 1) ) return faostatus; mrabp->rab$l_rbf = (char *) mrec; mrabp->rab$w_rsz = mreclen + MSG$K_BODY_POS; mrec->msg$l__date= Date; grec->grp$l_dateup= Date; if ( status != RMS$_RNF ) { mrec->msg$t_mid[0] = '>'; mrabp->rab$w_rsz = mreclen; } if ( (1 & (status = sys$put (mrabp))) ) { grabp->rab$l_rbf = (char *) grec; grabp->rab$w_rsz = sizeof(GRPREC); status = sys$put (grabp); } sys$free(grabp); return status;; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Performs a retrieving message in the given range, by using limit key. ** ** FORMAL PARAMETERS: ** ** mrabp: a pointer to RAB structure, message atabase ** grec: a pointer to current group ** from: a start number of message index ** to: an end number of message index ** mrec: a pointer to message record to insert into databases ** mreclen: a length of the message record ** LimKey: a limit key context ** LimKeysz: a limit key context size ** ** RETURN VALUE: ** ** RMS status ** **-- */ int MsgDBget_byRange ( struct RAB *mrabp, GRPREC *grec, ulong from, ulong to, MSGREC *mrec, ushort *msgreclen, char *LimKey, ushort *LimKeysz ) { int status; struct dsc$descriptor_s out_dsc; mrabp->rab$b_krf = MSG$K_GID_REF; mrabp->rab$l_ubf = (char *) mrec; mrabp->rab$w_usz = sizeof(MSGREC); mrabp->rab$v_nlk = 1; if ( !(*LimKeysz) ) { INIT_SDESC(out_dsc,sizeof(mrec->msg$t_gid),LimKey); if ( !(1 & (status = sys$fao(&msggrp_fao,LimKeysz,&out_dsc, &grec->grp$b_grplen,to))) ) return status; INIT_SDESC(out_dsc,sizeof(mrec->msg$t_gid),mrec->msg$t_gid); if ( !(1 & (status = sys$fao(&msggrp_fao,LimKeysz,&out_dsc, &grec->grp$b_grplen,from))) ) return status; mrabp->rab$b_rac = RAB$C_KEY; mrabp->rab$b_krf = MSG$K_GID_REF; mrabp->rab$l_kbf = mrec->msg$t_gid; mrabp->rab$b_ksz = *LimKeysz; status = sys$get (mrabp); *msgreclen = mrabp->rab$w_rsz - MSG$K_BODY_POS; return status; } mrabp->rab$b_rac = RAB$C_SEQ; mrabp->rab$v_lim = 1; mrabp->rab$l_kbf = LimKey; mrabp->rab$b_ksz = *LimKeysz; status = sys$get (mrabp); *msgreclen = mrabp->rab$w_rsz - MSG$K_BODY_POS; return status; } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Retrieve a group record from suck&feed database file. ** ** FORMAL PARAMETERS: ** ** rabp: a pointer to RAB structure ** fsrec: a pointer to retrieved feed&suck record ** ** RETURN VALUE: ** ** RMS status ** **-- */ int FeedSuckDBget ( struct RAB *rabp, FSREC *fsrec ) { long status; rabp->rab$b_rac = RAB$C_KEY; rabp->rab$l_kbf = fsrec->fs$t_hash; rabp->rab$b_ksz = sizeof(fsrec->fs$t_hash); rabp->rab$l_ubf = (char *) fsrec; rabp->rab$w_usz = sizeof(FSREC); return sys$get (rabp); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Put/Update a group record into suck&feed database file. ** ** FORMAL PARAMETERS: ** ** rabp: a pointer to RAB structure ** fsrec: a pointer to retrieved feed&suck record ** ** RETURN VALUE: ** ** RMS status ** **-- */ int FeedSuckDBput ( struct RAB *rabp, FSREC *fsrec ) { rabp->rab$b_rac = RAB$C_KEY; rabp->rab$l_kbf = fsrec->fs$t_hash; rabp->rab$b_ksz = FS$K_FS_LEN; rabp->rab$l_rbf = (char *) fsrec; rabp->rab$w_rsz = sizeof(FSREC); return sys$put (rabp); } /* **++ ** FUNCTIONAL DESCRIPTION: ** ** Delete a record designated by an article Id from the database file. ** ** FORMAL PARAMETERS: ** ** mrabp: a pointer to RAB structure ** msgid: a message id to looking for ** msgidlen: a length of the message id ** ** RETURN VALUE: ** ** RMS status ** **-- */ int MsgDBdel_byId ( struct RAB *mrabp, char *msgid, ushort msgidlen ) { int status; /* ** Setup a RAB to searching */ mrabp->rab$b_krf = MSG$K_MID_REF; mrabp->rab$b_rac = RAB$C_KEY; mrabp->rab$l_kbf = msgid; mrabp->rab$b_ksz = msgidlen; mrabp->rab$v_nlk = 0; /* ** Search and lock a message record */ if ( 1 & (status = sys$find (mrabp)) ) if ( 1 & (status = sys$delete(mrabp)) ) return status; }