home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Src / qmgr / tables.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  44.8 KB  |  2,084 lines

  1. /* tables.c: table handling routines */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Src/qmgr/RCS/tables.c,v 6.0 1991/12/18 20:27:38 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Src/qmgr/RCS/tables.c,v 6.0 1991/12/18 20:27:38 jpo Rel $
  9.  *
  10.  * $Log: tables.c,v $
  11.  * Revision 6.0  1991/12/18  20:27:38  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include "util.h"
  19. #include "types.h"
  20. #include "qmgr.h"
  21.  
  22. /* Variables */
  23.  
  24. MsgStruct    *msg_hash[QUE_HASHSIZE];
  25. Chanlist    **chan_list;
  26. int        nchanlist = 0;
  27.  
  28. /* Procedures & functions */
  29.  
  30. extern    char    *strdup ();
  31. int        hash ();
  32. void        addtochan ();
  33. void        create_chan ();
  34. Mtalist        *findmtalist ();
  35. MsgStruct    *find_msg ();
  36. Mlist        *findmtamsg ();
  37. Chanlist    *delete_chan = NULLCHANLIST;
  38. Chanlist    *loader_chan = NULLCHANLIST;
  39. Chanlist    *trash_chan = NULLCHANLIST;
  40. Chanlist    *timeout_chan = NULLCHANLIST;
  41. Chanlist    *warn_chan = NULLCHANLIST;
  42. Chanlist    *findchanlist ();
  43. static void    mcontrol ();
  44. static int    chaninsert ();
  45. static int    insertinmta ();
  46. static int     addmtaid ();
  47. static int    filtermatch ();
  48. static int    compmpduid ();
  49. static int    nullstrcmp ();
  50. static int    bind_result ();
  51. static int     bind_error ();
  52. static void    setchannels ();
  53.  
  54. void        insertinchan ();
  55. void        insertindelchan ();
  56. void        insertindrchan ();
  57. void        cache_clear ();
  58. void        cache_set ();
  59. void        cache_inc ();
  60. void        freems ();
  61. void        freefilter ();
  62.  
  63. int        zapmtamsg ();
  64.  
  65. /* External functions */
  66. extern struct type_Qmgr_PrioritisedChannel *lpchan ();
  67. extern struct type_Qmgr_ChannelInfo *lchani ();
  68. extern struct type_Qmgr_PrioritisedMta *lpmta ();
  69. extern struct type_Qmgr_MtaInfo    *lmta ();
  70. extern struct type_Qmgr_ProcStatus *lstatus ();
  71. extern struct type_Qmgr_MsgStruct *lmessage ();
  72. extern struct type_Qmgr_MsgStruct *l_cm_message ();
  73. extern struct type_UNIV_UTCTime *ltime ();
  74. extern void addtorunq (), delfromrunq ();
  75. extern void investigate_mta ();
  76. extern MsgStruct *newmsgstruct ();
  77. extern Filter *newfilter ();
  78.  
  79. extern int maxchansrunning, nchansrunning;
  80.  
  81. #define STR2QB(s)    str2qb ((s), strlen((s)), 1)
  82.  
  83. static int check_credentails (cb, name, passwd)
  84. Connblk *cb;
  85. char    *name, *passwd;
  86. {
  87.     extern char *crypt ();
  88.     char     result[BUFSIZ];
  89.     static Table    *auth= NULLTBL;
  90.     char    *av[30];
  91.     int    ac;
  92.     char    *tbl_passwd = NULLCP;
  93.     char    *tbl_rights = NULLCP;
  94.     char    *tbl_name;
  95.     extern char *qmgr_auth_tbl;
  96.  
  97.     cb -> cb_authenticated = 0;
  98.     if (auth == NULLTBL) {
  99.         if ((auth = tb_nm2struct(qmgr_auth_tbl)) == NULLTBL) {
  100.             PP_NOTICE (("Accepted Limited Access for %s",
  101.                     name));
  102.             return int_Qmgr_result_acceptedLimitedAccess;
  103.         }
  104.     }
  105.     if (name == NULLCP)
  106.         tbl_name = "anon";
  107.     else    tbl_name = name;
  108.  
  109.     if (tb_k2val (auth, tbl_name, result, TRUE) == NOTOK) {
  110.         if (name == NULLCP) {
  111.             PP_NOTICE (("Accepted Limited Access for %s",
  112.                     tbl_name));
  113.             return int_Qmgr_result_acceptedLimitedAccess;
  114.         }
  115.         else {
  116.             PP_NOTICE (("Refused connection for %s", tbl_name));
  117.             return NOTOK;
  118.         }
  119.     }
  120.  
  121.     ac = sstr2arg (result, 30, av, ", \t");
  122.     for (ac --; ac >= 0; ac --) {
  123.         char    *cp;
  124.  
  125.         if ((cp = index (av[ac], '=')) == NULLCP)
  126.             tbl_passwd = av[ac];
  127.         else {
  128.             *cp ++ = '\0';
  129.             if (lexequ (av[ac], "passwd") == 0)
  130.                 tbl_passwd = cp;
  131.             else if (lexequ (av[ac], "rights") == 0)
  132.                 tbl_rights = cp;
  133.         }
  134.     }
  135.  
  136.     if (tbl_passwd) {
  137.         if (passwd == NULLCP) {
  138.             PP_LOG (LLOG_EXCEPTIONS,
  139.                 ("Password required, none given for %s",
  140.                  tbl_name));
  141.             return NOTOK;
  142.         }
  143.         if (strcmp (tbl_passwd, crypt (passwd, tbl_passwd)) != 0) {
  144.             PP_LOG (LLOG_EXCEPTIONS,
  145.                 ("Password mismatch for %s", tbl_name));
  146.             return NOTOK;
  147.         }
  148.     }
  149.     /* now authenticated, if required */
  150.  
  151.     if (tbl_rights == NULLCP) {
  152.         PP_NOTICE (("Limited Access granted for %s (no default rights)",
  153.                 tbl_name));
  154.         cb -> cb_authenticated = 0;
  155.         return int_Qmgr_result_acceptedLimitedAccess;
  156.     }
  157.     if (lexequ (tbl_rights, "none") == 0) {
  158.         PP_NOTICE (("%s explicitly refused", tbl_name));
  159.         return NOTOK;
  160.     }
  161.     if (lexequ (tbl_rights, "limited") == 0) {
  162.         PP_NOTICE (("Limited access granted for %s", tbl_name));
  163.         return int_Qmgr_result_acceptedLimitedAccess;
  164.     }
  165.     if (lexequ (tbl_rights, "full") == 0) {
  166.         PP_NOTICE (("Full Access granted for %s", tbl_name));
  167.         cb -> cb_authenticated = 1;
  168.         return int_Qmgr_result_acceptedFullAccess;
  169.     }
  170.     PP_LOG (LLOG_EXCEPTIONS, ("Unknown rights '%s'", tbl_rights));
  171.     return NOTOK;
  172. }
  173.  
  174. int start_routine (sd, acs, pep, npe)
  175. int    sd;
  176. struct AcSAPstart *acs;
  177. PE    *pep;
  178. int    *npe;
  179. {
  180.     struct type_Qmgr_BindArgument *ba;
  181.     Connblk *cb;
  182.  
  183.     PP_TRACE (("start_routine (%d)", sd));
  184.     *pep = NULLPE;
  185.     cb = newcblk (cb_responder);
  186.     cb -> cb_fd = sd;
  187.  
  188.     *npe = 0;
  189.     if (acs -> acs_ninfo == 0) {
  190.         cb -> cb_authenticated = 0;
  191.         return bind_result (pep, npe, cb,
  192.                     int_Qmgr_result_acceptedLimitedAccess);
  193.     }
  194.     
  195.     if (decode_Qmgr_BindArgument (acs -> acs_info[0], 1,
  196.                        NULLVP, NULLIP, &ba) == NOTOK) {
  197.         PP_LOG (LLOG_EXCEPTIONS, ("failed to parse connect data [%s]",
  198.                       PY_pepy));
  199.         cb -> cb_authenticated = 0;
  200.         return bind_result (pep, npe, cb,
  201.                      int_Qmgr_result_acceptedLimitedAccess);
  202.     }
  203.     if (ba -> offset == type_Qmgr_BindArgument_noAuthentication) {
  204.         cb -> cb_authenticated = 0;
  205.         free_Qmgr_BindArgument (ba);
  206.         if (check_credentails (cb, NULLCP, NULLCP) == NOTOK)
  207.             return bind_error (pep, npe, cb,
  208.                        int_Qmgr_reason_badCredentials);
  209.         return bind_result (pep, npe, cb,
  210.                     int_Qmgr_result_acceptedLimitedAccess);
  211.     }
  212.  
  213.     if (ba -> offset == type_Qmgr_BindArgument_weakAuthentication) {
  214.         char    *username;
  215.         char    *pass;
  216.         int    result;
  217.  
  218.         username = qb2str (ba -> un.weakAuthentication -> username);
  219.         if (ba -> un.weakAuthentication -> passwd)
  220.             pass = qb2str (ba -> un.weakAuthentication -> passwd);
  221.         else pass = NULLCP;
  222.  
  223.         result = check_credentails (cb, username, pass);
  224.  
  225.         if (username) free (username);
  226.         if (pass) free (pass);
  227.         free_Qmgr_BindArgument (ba);
  228.         if (result == NOTOK)
  229.             return bind_error (pep, npe, cb,
  230.                        int_Qmgr_reason_badCredentials);
  231.         else
  232.             return bind_result (pep, npe, cb, result);
  233.     }
  234.     free_Qmgr_BindArgument (ba);
  235.     return bind_error (pep, npe, cb, int_Qmgr_reason_congested);
  236. }
  237.  
  238.  
  239. static int bind_result (pep, npe, cb, type)
  240. PE    *pep;
  241. int    *npe;
  242. Connblk *cb;
  243. int    type;
  244. {
  245.     struct type_Qmgr_BindResult *br;
  246.     extern char *qmgr_hostname, *ppversion;
  247.  
  248.     PP_TRACE (("bind_result"));
  249.  
  250.     br = (struct type_Qmgr_BindResult *) smalloc (sizeof *br);
  251.     br -> result = type;
  252.     br -> information = STR2QB (qmgr_hostname);
  253.     br -> version = STR2QB (ppversion);
  254.  
  255.     if (encode_Qmgr_BindResult (pep, 1, NULLCP, 0, br) == NOTOK) {
  256.         PP_LOG (LLOG_EXCEPTIONS, ("failed to encode BindResult [%s]",
  257.             PY_pepy));
  258.         free_Qmgr_BindResult (br);
  259.         return bind_error (pep, npe, cb,
  260.                    int_Qmgr_reason_congested);
  261.     }
  262.     (*pep) -> pe_context = 3;
  263.     free_Qmgr_BindResult (br);
  264.     *npe = 1;
  265.     return ACS_ACCEPT;
  266. }
  267.  
  268. static int bind_error (pep, npe, cb, type)
  269. PE    *pep;
  270. int    *npe;
  271. Connblk *cb;
  272. int    type;
  273. {
  274.     struct type_Qmgr_BindError *be;
  275.  
  276.     PP_TRACE (("bind_error"));
  277.  
  278.     be = (struct type_Qmgr_BindError *) smalloc (sizeof *be);
  279.     be -> reason = type;
  280.     be -> information = NULL;
  281.  
  282.     cb -> cb_fd = NOTOK;
  283.     freecblk (cb);
  284.     if (encode_Qmgr_BindError (pep, 1, NULLCP, 0, be) == NOTOK) {
  285.         PP_LOG (LLOG_EXCEPTIONS,
  286.             ("Failed to build BindError [%s]", PY_pepy));
  287.         *pep = NULLPE;
  288.         *npe = 0;
  289.         free_Qmgr_BindError (be);
  290.         return ACS_PERMANENT;
  291.     }
  292.     (*pep) -> pe_context = 3;
  293.     *npe = 1;
  294.     free_Qmgr_BindError (be);
  295.     return ACS_PERMANENT;
  296. }
  297.  
  298. int add_msg (sd, msg, rox, roi)
  299. int sd;
  300. struct type_Qmgr_MsgStruct *msg;
  301. struct RoSAPinvoke *rox;
  302. struct RoSAPindication *roi;
  303. {
  304.     MsgStruct *ms, *oldms;
  305.     int    result;
  306.  
  307.     PP_TRACE (("add_msg (%d, msg, rox, roi)", sd));
  308.  
  309.     if (submission_disabled == 1)    /* not submitting right now */
  310.         return error (sd, error_Qmgr_congested, (caddr_t) NULL,
  311.                   rox, roi);
  312.  
  313.     if ((ms = newmsgstruct (msg)) == NULLMS)
  314.         return error (sd, error_Qmgr_congested, (caddr_t) NULL,
  315.                   rox, roi);
  316.  
  317.     if (ms -> inchan && ms -> inchan -> ch_chan_type == CH_IN) {
  318.         Chanlist *clp;
  319.  
  320.         if ((clp = findchanlist (ms -> inchan)) &&
  321.             clp -> lastsuccess < ms -> age)
  322.             clp -> lastsuccess = ms -> age;
  323.     }
  324.  
  325.     if ((oldms = find_msg (ms -> queid)) != NULLMS) {
  326.         result = updatemessage (oldms, ms);
  327.         freems (ms);
  328.     }
  329.     else
  330.         result = insertmessage (ms);
  331.  
  332.     if (result == OK)
  333.         return RyDsResult (sd, rox -> rox_id, (caddr_t) NULL,
  334.                    ROS_NOPRIO, roi);
  335.     else
  336.         return error (sd, error_Qmgr_congested, (caddr_t) NULL,
  337.                   rox, roi);
  338. }
  339.  
  340. /* ARGSUSED */
  341. int updatemessage (old, new)
  342. MsgStruct *old, *new;
  343. {
  344.     PP_TRACE (("updatemessage ()"));
  345.     /* to be written !! */
  346.     PP_NOTICE (("update on message %s - ignored", new -> queid));
  347.  
  348.     return OK;
  349. }
  350.  
  351. int insertmessage (ms)
  352. MsgStruct *ms;
  353. {
  354.     MsgStruct **msp;
  355.     
  356.  
  357.     PP_TRACE (("insertmessage ()"));
  358.  
  359.     for (msp = &msg_hash[hash(ms -> queid, QUE_HASHSIZE)]; *msp;
  360.          msp = &(*msp) -> ms_forw)
  361.         continue;
  362.  
  363.     (*msp) = ms;
  364.  
  365.     switch (chaninsert (ms)) {
  366.         case NOTOK: /* back out change */
  367.         freems (ms);
  368.         (*msp) = NULLMS;
  369.         return NOTOK;
  370.         case OK: /* normal */
  371.         stats.n_messages_in ++;
  372.         break;
  373.         case DONE: /* deletion */
  374.         break;
  375.     }
  376.     return OK;
  377. }
  378.  
  379. /* ARGSUSED */
  380. int    read_msg (sd, rma, rox, roi)
  381. int    sd;
  382. struct type_Qmgr_ReadMessageArgument *rma;
  383. struct RoSAPinvoke *rox;
  384. struct RoSAPindication *roi;
  385. {
  386.     MsgStruct **msp, *ms;
  387.     struct type_Qmgr_MsgStructList **mlp;
  388.     struct type_Qmgr_MsgList *base;
  389.     Filter    *filter;
  390.  
  391.     PP_TRACE (("read_msg (%d)", sd));
  392.  
  393.     if ((base = (struct type_Qmgr_MsgList *) calloc (1, sizeof *base))
  394.         == NULL)
  395.         return error (sd, error_Qmgr_congested, (caddr_t) NULL,
  396.                   rox, roi);
  397.     mlp = &base -> msgs;
  398.  
  399.     filter = newfilter (rma -> filters);
  400.  
  401.     for (msp = msg_hash; msp < &msg_hash[QUE_HASHSIZE]; msp++) {
  402.         for (ms = *msp; ms; ms = ms -> ms_forw) {
  403.             if (filtermatch (filter, ms)) {
  404.                 *mlp = (struct type_Qmgr_MsgStructList *)
  405.                     calloc (1, sizeof (**mlp));
  406.                 
  407.                 (*mlp) -> MsgStruct = lmessage (ms);
  408.                 mlp = &(*mlp) -> next;
  409.             }
  410.         }
  411.     }
  412.     freefilter (filter);
  413.  
  414.     if (RyDsResult (sd, rox -> rox_id, (caddr_t) base, ROS_NOPRIO, roi)
  415.         == NOTOK)
  416.         ros_adios (&roi -> roi_preject, "RESULT");
  417.     free_Qmgr_MsgList (base);
  418.  
  419.     return OK;
  420. }
  421.  
  422. /* ARGSUSED */
  423. int    channel_list (sd, arg, rox, roi)
  424. int    sd;
  425. struct type_UNIV_UTCTime *arg;
  426. struct RoSAPinvoke *rox;
  427. struct RoSAPindication *roi;
  428. {
  429.     struct type_Qmgr_ChannelReadResult *crr;
  430.     struct type_Qmgr_PrioritisedChannelList **list;
  431.     Chanlist    **clp;
  432.  
  433.     PP_TRACE (("channel_list (%d)", sd));
  434.  
  435.     crr = (struct type_Qmgr_ChannelReadResult *) smalloc (sizeof *crr);
  436.     list = &crr -> channels;
  437.     crr -> channels = NULL;
  438.     crr -> load1 = 100 * stats.runnable_chans;
  439.     crr -> load2 = 100 * stats.ops_sec;
  440.     crr -> currchans = nchansrunning;
  441.     crr -> maxchans = maxchansrunning;
  442.  
  443.     for (clp = chan_list; clp < &chan_list[nchanlist]; clp ++) {
  444.         *list = (struct type_Qmgr_PrioritisedChannelList *)
  445.             calloc (1, sizeof (**list));
  446.  
  447.         if (*list == NULL ||
  448.             ((*list) -> PrioritisedChannel = lpchan (*clp)) == NULL) {
  449.             free_Qmgr_ChannelReadResult (crr);
  450.             return error (sd, error_Qmgr_congested, (caddr_t) NULL,
  451.                       rox, roi);
  452.         }
  453.  
  454.         list = &((*list) -> next);
  455.     }
  456.  
  457.     if (RyDsResult (sd, rox -> rox_id, (caddr_t) crr, ROS_NOPRIO, roi)
  458.         == NOTOK)
  459.         ros_adios (&roi -> roi_preject, "RESULT");
  460.  
  461.     free_Qmgr_ChannelReadResult (crr);
  462.     return OK;
  463. }
  464.  
  465. int chan_control (sd, in, rox, roi)
  466. int    sd;
  467. struct type_Qmgr_ChannelControl *in;
  468. struct RoSAPinvoke *rox;
  469. struct RoSAPindication *roi;
  470. {
  471.     Chanlist *clp;
  472.     struct type_Qmgr_PrioritisedChannelList *pcl;
  473.     struct type_Qmgr_PrioritisedChannel *pc;
  474.     Connblk *cb;
  475.     char    *p;
  476.  
  477.     PP_TRACE (("chan_control (%d)", sd));
  478.  
  479.     if ((cb = findcblk (sd)) == NULLCB || cb -> cb_type != cb_responder)
  480.         return error (sd, error_Qmgr_congested, (caddr_t) NULL,
  481.                   rox, roi);
  482.     if (cb -> cb_authenticated == 0)
  483.         return error (sd, error_Qmgr_authenticationFailure,
  484.                   (caddr_t) NULL, rox, roi);
  485.  
  486.     p = qb2str (in -> channel);
  487.     clp = findchanlist (ch_nm2struct (p));
  488.     free (p);
  489.     if (clp == NULLCHANLIST)
  490.         return error (sd, error_Qmgr_noSuchChannel, (caddr_t) NULL,
  491.                   rox, roi);
  492.  
  493.     switch (in -> control -> offset) {
  494.         case type_Qmgr_Control_stop:
  495.         clp -> chan_enabled = 0;
  496.         clp -> chan_syssusp = 0;
  497.         break;
  498.  
  499.         case type_Qmgr_Control_start:
  500.         if (clp -> chan_enabled == 0)
  501.             clp -> chan_update = 1;
  502.         clp -> chan_enabled = 1;
  503.         clp -> chan_syssusp = 0;
  504.         break;
  505.  
  506.         case type_Qmgr_Control_cacheClear:
  507.         cache_clear (&clp -> cache);
  508.         clp -> chan_update = 1;
  509.         break;
  510.  
  511.         case type_Qmgr_Control_cacheAdd:
  512.         cache_set (&clp -> cache, in -> control -> un.cacheAdd);
  513.         clp -> nextevent = clp -> cache.cachetime;
  514.         break;
  515.  
  516.         default:
  517.         return error (sd, error_Qmgr_illegalOperation, (caddr_t) NULL,
  518.                   rox, roi);
  519.     }
  520.  
  521.     pcl = (struct type_Qmgr_PrioritisedChannelList *) malloc (sizeof *pcl);
  522.  
  523.     if ((pc = lpchan (clp)) == NULL)
  524.         return error (sd, error_Qmgr_congested, (caddr_t) NULL,
  525.                   rox, roi);
  526.  
  527.     pcl -> PrioritisedChannel = pc;
  528.     pcl -> next = NULL;
  529.     if (RyDsResult (sd, rox -> rox_id, (caddr_t) pcl, ROS_NOPRIO, roi)
  530.         == NOTOK)
  531.         ros_adios (&roi -> roi_preject, "RESULT");
  532.     free_Qmgr_PrioritisedChannelList (pcl);
  533.     return OK;
  534. }
  535.  
  536. /*ARGSUSED */
  537. int    chan_begin (sd, arg, rox, roi)
  538. int    sd;
  539. struct type_Qmgr_FilterList *arg;
  540. struct RoSAPinvoke *rox;
  541. struct RoSAPindication *roi;
  542. {
  543.     struct type_Qmgr_FilterList *out;
  544.  
  545.     PP_TRACE (("chan_begin (%d)", sd));
  546.  
  547.     out = (struct type_Qmgr_FilterList *) calloc (1, sizeof(*out));
  548.     if (out == NULL || (out -> Filter = (struct type_Qmgr_Filter *)
  549.                 calloc (1, sizeof (struct type_Qmgr_Filter)))
  550.         == NULL)
  551.         return error (sd, error_Qmgr_congested, (caddr_t) NULL,
  552.                   rox, roi);
  553.  
  554.     if (RyDsResult (sd, rox -> rox_id, (caddr_t) out, ROS_NOPRIO, roi)
  555.         == NOTOK)
  556.         ros_adios (&roi -> roi_preject, "RESULT");
  557.     free_Qmgr_FilterList (out);
  558.     return OK;
  559. }
  560.  
  561. int    mta_control (sd, arg, rox, roi)
  562. int    sd;
  563. struct type_Qmgr_MtaControl *arg;
  564. struct RoSAPinvoke *rox;
  565. struct RoSAPindication *roi;
  566. {
  567.     Chanlist    *clp = NULLCHANLIST;
  568.     Mtalist           *mlp;
  569.     struct type_Qmgr_MtaInfo *mta;
  570.     CHAN    *chan;
  571.     Connblk *cb;
  572.     char    *p;
  573.  
  574.     PP_TRACE (("mta_control (%d)", sd));
  575.  
  576.     if ((cb = findcblk (sd)) == NULLCB || cb -> cb_type != cb_responder)
  577.         return error (sd, error_Qmgr_congested, (caddr_t) NULL,
  578.                   rox, roi);
  579.     if (cb -> cb_authenticated == 0)
  580.         return error (sd, error_Qmgr_authenticationFailure,
  581.                   (caddr_t) NULL, rox, roi);
  582.  
  583.     p = qb2str (arg -> channel);
  584.     if ((chan = ch_nm2struct (p)) != NULLCHAN)
  585.         clp = findchanlist (chan);
  586.     free (p);
  587.  
  588.     if (clp == NULLCHANLIST)
  589.         return error (sd, error_Qmgr_noSuchChannel, (caddr_t) NULL,
  590.                   rox, roi);
  591.     p = qb2str (arg -> mta);
  592.     mlp = findmtalist (clp, p);
  593.     free(p);
  594.  
  595.     if (mlp == NULLMTALIST)
  596.         return error (sd, error_Qmgr_mtaNotInQueue, (caddr_t) NULL,
  597.                   rox, roi);
  598.  
  599.     switch (arg -> control -> offset) {
  600.         case type_Qmgr_Control_stop:
  601.         mlp -> mta_enabled = 0;
  602.         break;
  603.         case type_Qmgr_Control_start:
  604.         if (mlp -> mta_enabled == 0) {
  605.             mlp -> mta_changed = 1;
  606.             clp -> chan_update = 1;
  607.         }
  608.         mlp -> mta_enabled = 1;
  609.         break;
  610.         case type_Qmgr_Control_cacheClear:
  611.         cache_clear (&mlp -> cache);
  612.         mlp -> mta_changed = 1;
  613.         clp -> chan_update = 1;
  614.         remque (mlp);
  615.         insque (mlp, clp -> mtas -> mta_forw);
  616.         break;
  617.         case type_Qmgr_Control_cacheAdd:
  618.         cache_set (&mlp -> cache, arg -> control -> un.cacheAdd);
  619.         mlp -> mta_changed = 1;
  620.         clp -> chan_update = 1;
  621.         remque (mlp);
  622.         insque (mlp, clp -> mtas -> mta_back);
  623.         break;
  624.         default:
  625.         return error (sd, error_Qmgr_illegalOperation, (caddr_t) NULL,
  626.                   rox, roi);
  627.     }
  628.  
  629.     if ((mta = lmta (mlp, clp)) == NULL)
  630.         return error (sd, error_Qmgr_congested, (caddr_t) NULL,
  631.                   rox, roi);
  632.     if (RyDsResult (sd, rox -> rox_id, (caddr_t) mta, ROS_NOPRIO, roi)
  633.         == NOTOK)
  634.         ros_adios (&roi -> roi_preject, "RESULT");
  635.     free_Qmgr_MtaInfo (mta);
  636.     return OK;
  637. }
  638.  
  639. int    mta_read (sd, arg, rox, roi)
  640. int    sd;
  641. struct type_Qmgr_MtaRead *arg;
  642. struct RoSAPinvoke *rox;
  643. struct RoSAPindication *roi;
  644. {
  645.     Chanlist *clp;
  646.     struct type_Qmgr_PrioritisedMtaList **qmlpp,  *qmlp;
  647.     char    *p;
  648.     Mtalist *mlp;
  649.  
  650.     PP_TRACE (("mta_read (%d)", sd));
  651.  
  652.     qmlp = 0;
  653.     qmlpp = &qmlp;
  654.  
  655.     p = qb2str (arg -> channel);
  656.     clp = findchanlist (ch_nm2struct (p));
  657.     free (p);
  658.     if (clp == NULLCHANLIST)
  659.         return error (sd, error_Qmgr_noSuchChannel, (caddr_t) NULL,
  660.                   rox, roi);
  661.  
  662.     for (mlp = clp -> mtas -> mta_forw; mlp != clp -> mtas;
  663.          mlp = mlp -> mta_forw) {
  664.         *qmlpp = (struct type_Qmgr_PrioritisedMtaList *)
  665.             calloc (1, sizeof(**qmlpp));
  666.  
  667.         if (*qmlpp == NULL ||
  668.             ((*qmlpp) -> PrioritisedMta = lpmta (mlp, clp)) == NULL) {
  669.             free_Qmgr_PrioritisedMtaList (qmlp);
  670.             return error (sd, error_Qmgr_congested, (caddr_t) NULL,
  671.                       rox, roi);
  672.         }
  673.  
  674.         qmlpp = &((*qmlpp) -> next);
  675.     }
  676.  
  677.     if (RyDsResult (sd, rox -> rox_id, (caddr_t) qmlp, ROS_NOPRIO, roi)
  678.         == NOTOK)
  679.         ros_adios (&roi -> roi_preject, "RESULT");
  680.     free_Qmgr_PrioritisedMtaList (qmlp);
  681.     return OK;
  682. }
  683.  
  684. int msg_control (sd, arg, rox, roi)
  685. int    sd;
  686. struct type_Qmgr_MsgControl *arg;
  687. struct RoSAPinvoke *rox;
  688. struct RoSAPindication *roi;
  689. {
  690.     char    *q;
  691.     Reciplist *rl;
  692.     struct type_Qmgr_UserList *ul;
  693.     Connblk *cb;
  694.     MsgStruct *ms;
  695.  
  696.     PP_TRACE (("msg_control (%d)", sd));
  697.     if ((cb = findcblk (sd)) == NULLCB || cb -> cb_type != cb_responder)
  698.         return error (sd, error_Qmgr_congested, (caddr_t) NULL,
  699.                   rox, roi);
  700.     if (cb -> cb_authenticated == 0)
  701.         return error (sd, error_Qmgr_authenticationFailure,
  702.                   (caddr_t) NULL, rox, roi);
  703.  
  704.     q = qb2str (arg -> qid);
  705.     if ((ms = find_msg (q)) == NULLMS)
  706.         return error  (sd, error_Qmgr_noSuchChannel, (caddr_t)NULL,
  707.                    rox, roi);
  708.     for (rl = ms -> recips; rl; rl = rl -> rp_next) {
  709.         for (ul = arg -> users; ul; ul = ul -> next) {
  710.             if (ul -> RecipientId -> parm == rl -> id)
  711.                 mcontrol (ms, rl, arg -> control);
  712.         }
  713.     }
  714.     if (RyDsResult (sd, rox -> rox_id, (caddr_t) NULL, ROS_NOPRIO, roi)
  715.         == NOTOK)
  716.         ros_adios (&roi -> roi_preject, "RESULT");
  717.     return OK;
  718. }
  719.  
  720. static void mcontrol (ms, rl, ctrl)
  721. MsgStruct *ms;
  722. Reciplist    *rl;
  723. struct type_Qmgr_Control *ctrl;
  724. {
  725.     LIST_RCHAN    *cl;
  726.     char    *p;
  727.     Chanlist *clp = NULL;
  728.     Mlist *ml;
  729.     Mtalist *mlp;
  730.  
  731.     PP_TRACE (("mcontrol (%s, %d)", ms -> queid, rl -> id));
  732.  
  733.     switch (rl -> status) {
  734.         case ST_NORMAL:
  735.  
  736.         if ((cl = rl -> cchan) == NULL)
  737.             return;
  738.         clp = findchanlist (cl -> li_chan);
  739.         p = chan2mta (cl -> li_chan, rl);
  740.         break;
  741.  
  742.         case ST_DR:
  743.         {
  744.             Reciplist *rlp2;
  745.  
  746.             for (rlp2 = ms -> recips; rlp2; rlp2 = rlp2 -> rp_next)
  747.                 if (rlp2 -> id == 0)
  748.                     break;
  749.             if (rlp2 == NULL)
  750.                 return;
  751.             clp = findchanlist(rlp2 -> chans->li_chan);
  752.             
  753.             p = chan2mta (clp -> chan, rlp2);
  754.             break;
  755.         }
  756.  
  757.         case ST_DELETE:
  758.         clp = delete_chan;
  759.         p = chan2mta (delete_chan -> chan, rl);
  760.         break;
  761.  
  762.         case ST_TIMEOUT:
  763.         clp = timeout_chan;
  764.         p = chan2mta (timeout_chan -> chan, rl);
  765.         break;
  766.  
  767.         case ST_WARNING:
  768.         clp = warn_chan;
  769.         p = chan2mta (warn_chan -> chan, rl);
  770.         break;
  771.  
  772.         default:
  773.         return;
  774.  
  775.     }
  776.     if (clp == NULLCHANLIST)
  777.         return;
  778.  
  779.     if ((mlp = findmtalist (clp, p)) == NULLMTALIST)
  780.         return;
  781.  
  782.     for (ml = mlp -> msgs -> ml_forw; ml != mlp -> msgs;
  783.          ml = ml -> ml_forw) {
  784.         if (ml -> ms == ms)
  785.             break;
  786.     }
  787.     if (ml == mlp -> msgs)
  788.         return;
  789.  
  790.     switch (ctrl -> offset) {
  791.         case type_Qmgr_Control_stop:
  792.         rl -> msg_enabled = 0;
  793.         break;
  794.         case type_Qmgr_Control_start:
  795.         rl -> msg_enabled = 1;
  796.         break;
  797.         case type_Qmgr_Control_cacheClear:
  798.         cache_clear (&rl -> cache);
  799.         break;
  800.         case type_Qmgr_Control_cacheAdd:
  801.         cache_set (&rl -> cache, ctrl -> un.cacheAdd);
  802.         break;
  803.     }
  804.     mlp -> mta_changed = 1;
  805.     clp -> chan_update = 1;
  806. }
  807.  
  808. int qmgrcontrol (sd, op, rox, roi)
  809. int    sd;
  810. int    op;
  811. struct RoSAPinvoke *rox;
  812. struct RoSAPindication *roi;
  813. {
  814.     Connblk *cb;
  815.  
  816.     PP_TRACE (("qmgrcontrol (%d)", sd));
  817.  
  818.     if ((cb = findcblk (sd)) == NULLCB || cb -> cb_type != cb_responder)
  819.         return error (sd, error_Qmgr_congested, (caddr_t) NULL,
  820.                   rox, roi);
  821.     if (cb -> cb_authenticated == 0)
  822.         return error (sd, error_Qmgr_authenticationFailure,
  823.                   (caddr_t) NULL, rox, roi);
  824.     switch (op) {
  825.         case int_Qmgr_QMGROp_abort:
  826.         exit (0);
  827.         break;
  828.  
  829.         case int_Qmgr_QMGROp_gracefulTerminate:
  830.         setchannels (1);
  831.         opmode = OP_SHUTDOWN;
  832.         break;
  833.  
  834.         case int_Qmgr_QMGROp_restart:
  835.         setchannels (0);
  836.         opmode = OP_RESTART;
  837.         break;
  838.  
  839.         case int_Qmgr_QMGROp_rereadQueue:
  840.         if (loader_chan) {
  841.             cache_clear (&loader_chan -> cache);
  842.             loader_chan -> nextevent = current_time;
  843.         }
  844.         break;
  845.  
  846.         case int_Qmgr_QMGROp_disableSubmission:
  847.         submission_disabled = 1;
  848.         break;
  849.  
  850.         case int_Qmgr_QMGROp_enableSubmission:
  851.         submission_disabled = 0;
  852.         if (loader_chan) {
  853.             cache_clear (&loader_chan -> cache);
  854.             loader_chan -> nextevent = current_time;
  855.         }
  856.         break;
  857.  
  858.         case int_Qmgr_QMGROp_disableAll:
  859.         case int_Qmgr_QMGROp_enableAll:
  860.         setchannels (op == int_Qmgr_QMGROp_enableAll ? 1 : 0);
  861.         break;
  862.  
  863.         case int_Qmgr_QMGROp_increasemaxchans:
  864.         maxchansrunning ++;
  865.         break;
  866.  
  867.         case int_Qmgr_QMGROp_decreasemaxchans:
  868.         maxchansrunning --;
  869.         maxchansrunning = max (1, maxchansrunning);
  870.         break;
  871.  
  872.         default:
  873.         PP_LOG (LLOG_EXCEPTIONS,  ("Unknown operation %d", op));
  874.         break;
  875.     }
  876.     if (RyDsResult (sd, rox -> rox_id, (caddr_t) NULL, ROS_NOPRIO, roi)
  877.         == NOTOK)
  878.         ros_adios (&roi -> roi_preject, "RESULT");
  879.     return OK;
  880. }
  881.  
  882. int msgread (sd, mr, rox, roi)
  883. int    sd;
  884. struct type_Qmgr_MsgRead *mr;
  885. struct RoSAPinvoke *rox;
  886. struct RoSAPindication *roi;
  887. {
  888.     struct type_Qmgr_MsgStructList **qmlpp;
  889.     struct type_Qmgr_MsgList *base;
  890.     Mtalist *mlp;
  891.     Chanlist *clp;
  892.     Mlist *ml;
  893.     char    *p;
  894.  
  895.     PP_TRACE (("msgread (%d)", sd));
  896.  
  897.     p = qb2str (mr -> channel);
  898.     clp = findchanlist (ch_nm2struct (p));
  899.     free (p);
  900.     if (clp == NULLCHANLIST)
  901.         return error (sd, error_Qmgr_noSuchChannel, (caddr_t) NULL,
  902.                   rox, roi);
  903.  
  904.     p = qb2str (mr -> mta);
  905.     mlp = findmtalist (clp, p);
  906.     free (p);
  907.  
  908.     if (mlp == NULLMTALIST)
  909.         return error (sd, error_Qmgr_mtaNotInQueue, (caddr_t) NULL,
  910.                   rox, roi);
  911.  
  912.     base = (struct type_Qmgr_MsgList *) calloc (1, sizeof *base);
  913.     qmlpp = &base -> msgs;
  914.     
  915.     for (ml = mlp -> msgs -> ml_forw; ml != mlp -> msgs;
  916.          ml = ml -> ml_forw) {
  917.         *qmlpp = (struct type_Qmgr_MsgStructList *)
  918.             calloc (1, sizeof **qmlpp);
  919.         (*qmlpp) -> MsgStruct = l_cm_message (ml);
  920.         qmlpp = &(*qmlpp) -> next;
  921.     }
  922.  
  923.     if (RyDsResult (sd, rox -> rox_id, (caddr_t)base, ROS_NOPRIO, roi)
  924.         == NOTOK)
  925.         ros_adios (&roi -> roi_preject, "RESULT");
  926.     free_Qmgr_MsgList (base);
  927.  
  928.     return OK;
  929. }
  930.  
  931. int qmgrstatus (sd, rox, roi)
  932. int    sd;
  933. struct RoSAPinvoke *rox;
  934. struct RoSAPindication *roi;
  935. {
  936.     struct type_Qmgr_QmgrStatus *qs;
  937.     int i;
  938.  
  939.     PP_TRACE (("qmgrstatus (%d)", sd));
  940.  
  941.     if ((qs = (struct type_Qmgr_QmgrStatus *)malloc (sizeof *qs)) == NULL)
  942.         return error (sd, error_Qmgr_congested, (caddr_t)NULL,
  943.                   rox, roi);
  944.  
  945.     qs -> boottime = ltime(stats.boottime);
  946.     qs -> messagesIn = stats.n_messages_in;
  947.     qs -> messagesOut = stats.n_messages_out;
  948.     qs -> addrIn = stats.n_addr_in;
  949.     qs -> addrOut = stats.n_addr_out;
  950.     qs -> opsPerSec = stats.ops_sec * 100.0;
  951.     qs -> runnableChans = stats.runnable_chans * 100.0;
  952.     qs -> msgsInPerSec = stats.msg_sec_in * 100.0;;
  953.     qs -> msgsOutPerSec = stats.msg_sec_out * 100.0;
  954.     qs -> maxChans = maxchansrunning;
  955.     qs -> currChans = nchansrunning;
  956.     qs -> totalMsgs = qs -> totalVolume = qs -> totalDrs = 0;
  957.     for (i = 0; i < nchanlist; i++) {
  958.         qs -> totalMsgs += chan_list[i] -> num_msgs;
  959.         qs -> totalVolume += chan_list[i] -> volume;
  960.         qs -> totalDrs += chan_list[i] -> num_drs;
  961.     }
  962.     
  963.     if (RyDsResult (sd, rox -> rox_id, (caddr_t)qs, ROS_NOPRIO, roi)
  964.         == NOTOK)
  965.         ros_adios (&roi -> roi_preject, "RESULT");
  966.     free_Qmgr_QmgrStatus (qs);
  967.  
  968.     return OK;
  969. }
  970.  
  971. /* private functions */
  972.  
  973. /* Channel functions */
  974.  
  975. static int    chaninsert (ms)
  976. MsgStruct *ms;
  977. {
  978.     LIST_RCHAN    *clp;
  979.     Reciplist *rlp;
  980.     int    num = 0;
  981.  
  982.     PP_TRACE (("chaninsert ()"));
  983.  
  984.     for (rlp = ms -> recips; rlp; rlp = rlp -> rp_next) {
  985.  
  986.         if ( rlp -> id == 0)
  987.             continue;
  988.         num ++;
  989.         rlp -> status = ST_NORMAL;
  990.         if ((clp = rlp -> cchan) == NULL) {
  991.             insertindrchan (ms, rlp);
  992.             PP_NOTICE (("Message %s to %s added - DR",
  993.                     ms -> queid, rlp -> user));
  994.             continue;
  995.         }
  996.  
  997.         insertinchan (clp -> li_chan, ms, rlp,
  998.                   chan2mta (clp -> li_chan, rlp));
  999.         PP_NOTICE (("Message %s to %s added",
  1000.                 ms -> queid, rlp -> user));
  1001.     }
  1002.     if (num == 0) {
  1003.         ms -> recips -> cchan = NULL;
  1004.         insertindelchan (ms);
  1005.         PP_NOTICE (("Message %s added - for deletion", ms -> queid));
  1006.         return DONE;
  1007.     }
  1008.     else
  1009.         stats.n_addr_in += num;
  1010.     return OK;
  1011. }
  1012.  
  1013. static void add_mta_hash (clp, mlp)
  1014. Chanlist *clp;
  1015. Mtalist *mlp;
  1016. {
  1017.     int idx;
  1018.  
  1019.     idx = hash(mlp -> mtaname,MTA_HASHSIZE);
  1020.     mlp -> hash_next = clp -> mta_hash[idx];
  1021.     clp -> mta_hash[idx] = mlp;
  1022. }
  1023.  
  1024.  
  1025. void insertinchan (chan, ms, ri, mta)
  1026. CHAN *chan;
  1027. MsgStruct *ms;
  1028. Reciplist *ri;
  1029. char    *mta;
  1030. {
  1031.     Mtalist           *mlp;
  1032.     Chanlist    *clp;
  1033.  
  1034.     PP_TRACE (("insertinchan (%s, %s, id=%d, mta=%s)", chan -> ch_name,
  1035.            ms -> queid, ri -> id, mta));
  1036.  
  1037.     clp = findchanlist (chan);
  1038.     if (clp == NULLCHANLIST) {
  1039.         PP_LOG (LLOG_EXCEPTIONS, ("No channel for %s",
  1040.                       chan -> ch_name));
  1041.         return;
  1042.     }
  1043.     if ((mlp = findmtalist(clp, mta)) == NULLMTALIST) {
  1044.         mlp = (Mtalist *) calloc (1, sizeof *mlp);
  1045.         mlp -> msgs = (Mlist *) calloc (1, sizeof *mlp -> msgs);
  1046.         mlp -> msgs -> ml_back = mlp -> msgs -> ml_forw = mlp -> msgs;
  1047.         insque (mlp, clp -> mtas -> mta_back);
  1048.         mlp -> mtaname = strdup (mta);
  1049.         mlp -> mta_enabled = 1;
  1050.         mlp -> nextevent = current_time;
  1051.         mlp -> clp = clp;
  1052.         clp -> nmtas ++;
  1053.         if (clp -> mta_hash)
  1054.             add_mta_hash (clp, mlp);
  1055.             
  1056.         if (clp -> nmtas == 1)
  1057.             addtorunq (clp);
  1058.     }
  1059.     if (insertinmta (mlp, ms, ri, clp) == OK ) {
  1060.         if (ri -> status == ST_DR)
  1061.             clp -> num_drs ++;
  1062.         else
  1063.             clp -> num_msgs ++;
  1064.         clp -> volume += ms -> size;
  1065.         if (mlp -> nextevent < clp -> nextevent &&
  1066.             clp -> cache.cachetime < current_time)
  1067.             clp -> nextevent = mlp -> nextevent;
  1068.         if (clp -> oldest == 0 || ms -> age < clp -> oldest)
  1069.             clp -> oldest = ms -> age;
  1070.         if (mlp -> oldest == 0 || ms -> age < mlp -> oldest)
  1071.             mlp -> oldest = ms -> age;
  1072.         
  1073.     }
  1074. }
  1075.  
  1076. void insertindelchan (ms)
  1077. MsgStruct *ms;
  1078. {
  1079.     Reciplist *ri, *ri2;
  1080.  
  1081.     PP_TRACE (("insertindelchan ()"));
  1082.  
  1083.     if (delete_chan == NULLCHANLIST) {
  1084.         PP_LOG(LLOG_EXCEPTIONS, ("No delete channel!"));
  1085.         return;
  1086.     }
  1087.  
  1088.     ri = ms -> recips;
  1089.     ri -> status = ST_DELETE;
  1090.     ri2 = ri -> rp_next ? ri -> rp_next : ri;
  1091.     insertinchan (delete_chan -> chan, ms, ri, 
  1092.               chan2mta(delete_chan -> chan, ri2));
  1093. }
  1094.  
  1095. void insertindrchan (ms, rlp)
  1096. MsgStruct *ms;
  1097. Reciplist *rlp;
  1098. {
  1099.     Reciplist *r;
  1100.     LIST_RCHAN    *cp;
  1101.  
  1102.     PP_TRACE (("insertindrchan ()"));
  1103.  
  1104.     rlp -> status = ST_DR;
  1105.     for (r = ms -> recips; r; r = r -> rp_next)
  1106.         if (r -> id == 0)
  1107.             break;
  1108.     if (r == NULLRL)
  1109.         return;
  1110.     if ((cp = r -> cchan) == NULL) {
  1111.         PP_LOG (LLOG_EXCEPTIONS, ("DR chan appears to have finished"));
  1112.         return;
  1113.     }
  1114.     insertinchan (cp -> li_chan, ms, rlp, chan2mta (cp -> li_chan, r));
  1115. }
  1116.  
  1117. Chanlist *findchanlist (chan)
  1118. CHAN    *chan;
  1119. {
  1120.     Chanlist    **clpp;
  1121.  
  1122.     if (chan == NULLCHAN)
  1123.         return NULLCHANLIST;
  1124.  
  1125.     for (clpp = chan_list; clpp < &chan_list[nchanlist]; clpp++)
  1126.         if ((*clpp) -> chan == chan)
  1127.             return *clpp;
  1128.  
  1129.     return NULLCHANLIST;
  1130. }
  1131.  
  1132. static void    setchannels (state)
  1133. int    state;
  1134. {
  1135.     Chanlist **cpp;
  1136.  
  1137.     for (cpp = chan_list; cpp < &chan_list[nchanlist]; cpp++) {
  1138.         (*cpp) -> chan_enabled = state;
  1139.         (*cpp) -> chan_update = 1;
  1140.     }
  1141. }
  1142.  
  1143.  
  1144.  
  1145. static int chan_sort (clp1, clp2)
  1146. Chanlist **clp1, **clp2;
  1147. {
  1148.     switch ((*clp1) -> chan -> ch_chan_type) {
  1149.         case CH_WARNING:
  1150.         case CH_DELETE:
  1151.         case CH_QMGR_LOAD:
  1152.         case CH_DEBRIS:
  1153.         case CH_TIMEOUT:
  1154.         case CH_SHAPER:
  1155.         switch ((*clp2) -> chan -> ch_chan_type) {
  1156.             case CH_BOTH:
  1157.             case CH_OUT:
  1158.             case CH_IN:
  1159.             return -1;
  1160.  
  1161.             default:
  1162.             break;
  1163.         }
  1164.         return 0;
  1165.  
  1166.         case CH_IN:
  1167.         switch ((*clp2) -> chan -> ch_chan_type) {
  1168.             case CH_IN:
  1169.             return 0;
  1170.  
  1171.             default:
  1172.             break;
  1173.         }
  1174.         return 1;
  1175.  
  1176.         case CH_BOTH:
  1177.         case CH_OUT:
  1178.         switch ((*clp2) -> chan -> ch_chan_type) {
  1179.             case CH_IN:
  1180.             return -1;
  1181.             case CH_OUT:
  1182.             case CH_BOTH:
  1183.             return ((*clp1) -> averaget -
  1184.                 (*clp2) -> averaget) * 100.0;
  1185.             default:
  1186.             break;
  1187.         }
  1188.         return 1;
  1189.     }
  1190.     return 0;
  1191. }
  1192.  
  1193. void sort_chans ()
  1194. {
  1195.     int i;
  1196.  
  1197.     if (nchanlist)
  1198.         qsort ((char *)chan_list, nchanlist,
  1199.                sizeof (Chanlist *), (IFP)chan_sort);
  1200.     PP_TRACE (("Channels resorted"));
  1201.     for (i = 0; i < nchanlist; i++)
  1202.         PP_TRACE (("Channel %d - %s (%g)", i,
  1203.                 chan_list[i] -> channame,
  1204.                 chan_list[i] -> averaget));
  1205. }
  1206.  
  1207.  
  1208. int delfromchan (clp, mlp, ml, rno)
  1209. Chanlist *clp;
  1210. Mtalist *mlp;
  1211. Mlist    *ml;
  1212. int    rno;
  1213. {
  1214.     int    i;
  1215.     int st = ST_NORMAL;
  1216.  
  1217.     PP_TRACE (("delfromchan (chan=%s, id=%d)",
  1218.         clp -> channame, rno));
  1219.  
  1220.     msg_unlock (ml -> ms);
  1221.  
  1222.     for (i = 0; i < ml -> rcount; i++)
  1223.         if (rno == ml -> recips[i] -> id)
  1224.             break;
  1225.     if (i < ml -> rcount) {
  1226.         st = ml -> recips[i] -> status;
  1227.         ml -> recips[i] -> ml = NULLMLIST;
  1228.         for (i++; i < ml -> rcount; i++)
  1229.             ml -> recips[i-1] = ml -> recips[i];
  1230.     }
  1231.     else
  1232.         PP_LOG (LLOG_EXCEPTIONS, ("can't locate correct recipient"));
  1233.     ml -> rcount --;
  1234.     if (ml -> rcount == 0) {
  1235.         ml -> recips = NULL;
  1236.         return zapmtamsg (ml, mlp, clp, st);
  1237.     }
  1238.     return 0;
  1239. }
  1240.  
  1241. /* Host functions */
  1242.  
  1243. static int csort_prio (ml1, ml2)
  1244. Mlist    *ml1, *ml2;
  1245. {
  1246.     if (ml1 -> ms -> priority == ml2 -> ms -> priority)
  1247.         return 0;
  1248.     if (ml1 -> ms -> priority == int_Qmgr_Priority_high)
  1249.         return 1;
  1250.     if (ml2 -> ms -> priority == int_Qmgr_Priority_high)
  1251.         return -1;
  1252.     if (ml1 -> ms -> priority == int_Qmgr_Priority_normal)
  1253.         return 1;
  1254.     if (ml1 -> ms -> priority == int_Qmgr_Priority_normal)
  1255.         return -1;
  1256.     return 0;
  1257. }
  1258.  
  1259. static int csort_time (ml1, ml2)
  1260. Mlist    *ml1, *ml2;
  1261. {
  1262.     if (ml1 -> ms -> age < ml2 -> ms -> age)
  1263.         return 1;
  1264.     if (ml2 -> ms -> age < ml1 -> ms -> age)
  1265.         return -1;
  1266.     return 0;
  1267. }
  1268.  
  1269. static int csort_size (ml1, ml2)
  1270. Mlist    *ml1, *ml2;
  1271. {
  1272.     if (ml1 -> ms -> size < ml2 -> ms -> size)
  1273.         return 1;
  1274.     if (ml2 -> ms -> size > ml1 -> ms -> size)
  1275.         return -1;
  1276.     return 0;
  1277. }
  1278.  
  1279. static mtaenqueue (ml, mlp, clp)
  1280. Mlist    *ml;
  1281. Mtalist  *mlp;
  1282. Chanlist *clp;
  1283. {
  1284.     int    i, msort;
  1285.     Mlist    *m;
  1286.     IFP    sfnx[CH_MAX_SORT - 1];
  1287.  
  1288.     if (clp -> chan -> ch_sort[1] == 0) {
  1289.         insque (ml, mlp -> msgs -> ml_back);
  1290.         return;
  1291.     }
  1292.  
  1293.     msort = 0;
  1294.     for (i = 1; i < CH_MAX_SORT && clp -> chan -> ch_sort[i]; i++) {
  1295.         switch (clp -> chan -> ch_sort[i]) {
  1296.             case CH_SORT_USR:
  1297.             case CH_SORT_MTA:
  1298.             PP_LOG (LLOG_EXCEPTIONS, ("Bad sort criteria for %s",
  1299.                           clp -> channame));
  1300.             insque (ml, mlp -> msgs -> ml_back);
  1301.             return;
  1302.  
  1303.             case CH_SORT_NONE:
  1304.             break;
  1305.  
  1306.             case CH_SORT_PRIORITY:
  1307.             sfnx[msort++] = csort_prio;
  1308.             continue;
  1309.             case CH_SORT_TIME:
  1310.             sfnx[msort++] = csort_time;
  1311.             continue;
  1312.             case CH_SORT_SIZE:
  1313.             sfnx[msort++] = csort_size;
  1314.             continue;
  1315.  
  1316.             default:
  1317.             break;
  1318.         }
  1319.         break;
  1320.     }
  1321.     for (m = mlp -> msgs -> ml_forw; m != mlp -> msgs; m = m -> ml_forw) {
  1322.  
  1323.         for (i = 0; i < msort; i++) {
  1324.             switch ((*sfnx[i])(m, ml)) {
  1325.                 case 0:
  1326.                 continue;
  1327.                 case -1:
  1328.                 insque (ml, m -> ml_back);
  1329.                 return;
  1330.  
  1331.                 case 1:
  1332.                 break;
  1333.             }
  1334.             break;
  1335.         }
  1336.     }
  1337.     insque (ml, mlp -> msgs -> ml_back);
  1338. }
  1339.  
  1340.  
  1341. static int insertinmta (mlp, ms, rlp, clp)
  1342. Mtalist           *mlp;
  1343. MsgStruct *ms;
  1344. Reciplist *rlp;
  1345. Chanlist *clp;
  1346. {
  1347.     Mlist    *ml;
  1348.     int    result;
  1349.  
  1350.     PP_TRACE (("insertinmta (%s, id=%d)",
  1351.            mlp -> mtaname, rlp -> id));
  1352.  
  1353.     if (mlp -> lastone && mlp -> lastone -> ms == ms) {
  1354.         PP_TRACE (("Lastone hit"));
  1355.         (void) addmtaid (mlp -> lastone, rlp);
  1356.         return DONE;
  1357.     }
  1358.     if (rlp -> status != ST_DR) {
  1359.         for (ml = mlp -> msgs -> ml_forw; ml != mlp -> msgs;
  1360.              ml = ml -> ml_forw) {
  1361.             if (ml -> ms -> m_locked)
  1362.                 continue;
  1363.             if (ml -> ms == ms) {
  1364.                 (void) addmtaid (ml, rlp);
  1365.                 mlp -> lastone = ml;
  1366.                 return DONE;
  1367.             }
  1368.         }
  1369.     }
  1370.     ml = (Mlist *) calloc (1, sizeof *ml);
  1371.     ml -> ms = ms;
  1372.     ml -> mlp = mlp;
  1373.  
  1374.     ms -> count ++;
  1375.     PP_TRACE (("Message reference count = %d", ms -> count));
  1376.  
  1377.     mtaenqueue (ml, mlp, clp);
  1378.  
  1379.     if ((result = addmtaid (ml, rlp)) == OK) {
  1380.         if (rlp -> status == ST_DR)
  1381.             mlp -> num_drs ++;
  1382.         else
  1383.             mlp -> num_msgs ++;
  1384.         mlp -> volume += ms -> size;
  1385.         if (mtaready(mlp))
  1386.             mlp -> nextevent = current_time;
  1387.     }
  1388.     mlp -> lastone = ml;
  1389.     return result;
  1390. }
  1391.  
  1392. static int addmtaid (ml, rlp)
  1393. Mlist    *ml;
  1394. Reciplist *rlp;
  1395. {
  1396.     Reciplist **ri;
  1397.  
  1398.     PP_TRACE (("addmtaid (%d)", rlp -> id));
  1399.  
  1400.     for (ri = ml -> recips; ri && ri < &ml->recips[ml->rcount];
  1401.          ri ++)
  1402.         if (*ri == rlp)
  1403.             return DONE;
  1404.  
  1405.     if (ml -> rcount == 0) {
  1406.         ml -> recips = (Reciplist **) malloc (sizeof (ri));
  1407.         ml -> recips[0] = rlp;
  1408.         rlp -> ml = ml;
  1409.         ml -> rcount = 1;
  1410.         return OK;
  1411.     }
  1412.  
  1413.     ml -> rcount ++;
  1414.     ml -> recips = (Reciplist **) realloc ((char *)ml -> recips,
  1415.                  (unsigned) ml -> rcount * sizeof (ri));
  1416.     ml -> recips[ml -> rcount - 1] = rlp;
  1417.     rlp -> ml = ml;
  1418.     return DONE;
  1419. }
  1420.  
  1421. Mtalist *findmtalist (clp, mta)
  1422. Chanlist *clp;
  1423. char    *mta;
  1424. {
  1425.     Mtalist           *mlp;
  1426.  
  1427.     PP_TRACE (("findmtalist (%s)", mta));
  1428.  
  1429.     if (clp -> mta_hash) {
  1430.         mlp = clp->mta_hash[hash(mta, MTA_HASHSIZE)];
  1431.         while (mlp) {
  1432.             if (lexequ (mta, mlp -> mtaname) == 0)
  1433.                 return mlp;
  1434.             mlp = mlp -> hash_next;
  1435.         }
  1436.         return NULLMTALIST;
  1437.     }
  1438.  
  1439.     for (mlp = clp -> mtas -> mta_forw; mlp != clp -> mtas;
  1440.          mlp = mlp -> mta_forw)
  1441.         if (lexequ (mta, mlp -> mtaname) == 0)
  1442.             return mlp;
  1443.     return NULLMTALIST;
  1444. }
  1445.  
  1446. int zapmta (mlp)
  1447. Mtalist    *mlp;
  1448. {
  1449.     Chanlist *clp;
  1450.     PP_TRACE (("zapmta (%s)", mlp -> mtaname));
  1451.  
  1452.     if (mlp -> num_msgs != 0 || mlp -> num_drs != 0) {
  1453.         PP_LOG (LLOG_EXCEPTIONS, ("zapmta called but msg not dead"));
  1454.         return ZAP_NONE;
  1455.     }
  1456.     if ((clp = mlp -> clp) != NULLCHANLIST)
  1457.         clp -> nmtas --;
  1458.     else {
  1459.         PP_LOG (LLOG_EXCEPTIONS, ("mta does not have chan"));
  1460.         return ZAP_NONE;
  1461.     }
  1462.     if (clp -> nmtas < 0) {
  1463.         PP_LOG (LLOG_EXCEPTIONS, ("mtas gone negative on %s (%d)",
  1464.                       clp -> channame, clp -> nmtas));
  1465.         clp -> chan_update = 1;
  1466.     }
  1467.     if (clp -> mta_hash) {    /* remove from hash list */
  1468.         Mtalist **mlpp;
  1469.  
  1470.         for (mlpp = &clp -> mta_hash[hash(mlp->mtaname, MTA_HASHSIZE)];
  1471.              *mlpp; mlpp = &(*mlpp) -> hash_next) {
  1472.             if (*mlpp == mlp) {
  1473.                 *mlpp = mlp -> hash_next;
  1474.                 break;
  1475.             }
  1476.         }
  1477.     }
  1478.     remque (mlp);
  1479.  
  1480.     if (mlp -> msgs)
  1481.         free ((char *) mlp -> msgs);
  1482.     if (mlp -> info)
  1483.         free (mlp -> info);
  1484.     if (mlp -> mtaname)
  1485.         free (mlp -> mtaname);
  1486.     free ((char *) mlp);
  1487.     if (clp && clp -> nmtas == 0) {
  1488.         delfromrunq (clp);
  1489.         clp -> oldest = 0;
  1490.     }
  1491.     return ZAP_MTA;
  1492. }
  1493.  
  1494. int zapmtamsg (ml, mlp, clp, st)
  1495. Mlist    *ml;
  1496. Mtalist    *mlp;
  1497. Chanlist    *clp;
  1498. int st;
  1499. {
  1500.     int result = ZAP_MSG;
  1501.  
  1502.     if (mlp == NULLMTALIST) {
  1503.         PP_LOG (LLOG_EXCEPTIONS, ("Null mtalist param"));
  1504.         return ZAP_NONE;
  1505.     }
  1506.     
  1507.     PP_TRACE (("zapmtamsg (mta=%s, chan=%s)",
  1508.         mlp -> mtaname, clp -> channame));
  1509.  
  1510.     if (st == ST_DR)
  1511.         clp -> num_drs --;
  1512.     else
  1513.         clp -> num_msgs --;
  1514.     clp -> volume -= ml -> ms -> size;
  1515.     if (ml -> ms -> age <= clp -> oldest)
  1516.         clp -> chan_update = 1;
  1517.     if (st == ST_DR)
  1518.         mlp -> num_drs --;
  1519.     else
  1520.         mlp -> num_msgs --;
  1521.     mlp -> volume -= ml -> ms -> size;
  1522.     if (ml -> ms -> age <= mlp -> oldest)
  1523.         mlp -> mta_changed = 1;
  1524.  
  1525.     remque (ml);
  1526.     ml -> ms -> count --;
  1527.     PP_TRACE (("Message reference count = %d",
  1528.         ml -> ms -> count));
  1529.  
  1530.     if (ml -> info)
  1531.         free (ml -> info);
  1532.     if (ml -> recips)
  1533.         free ((char *)ml -> recips);
  1534.     if (mlp -> lastone == ml)
  1535.         mlp -> lastone = NULL;
  1536.     free ((char *)ml);
  1537.  
  1538.     if (mlp -> num_msgs == 0 && mlp -> num_drs == 0)
  1539.         result |= zapmta (mlp);
  1540.     return result;
  1541. }
  1542.  
  1543. static Mlist *findnextml ();
  1544.  
  1545. /* Msg functions */
  1546.  
  1547. Mlist *nextmsg (clp, mlpp, lock, samemta)
  1548. Chanlist *clp;
  1549. Mtalist **mlpp;
  1550. int    lock;
  1551. int    samemta;
  1552. {
  1553.     Mlist    *ml;
  1554.     Mtalist *mlp;
  1555.  
  1556.     PP_TRACE (("nextmsg (clp, mlp)"));
  1557.  
  1558.     if ((mlp = *mlpp) != NULLMTALIST) {
  1559.         if (mlp -> mta_changed) {
  1560.             investigate_mta (mlp, current_time);
  1561.             mlp -> mta_changed = 0;
  1562.         }
  1563.         if (mlp -> error_count > 5 &&
  1564.             clp -> chan -> ch_sort[0] == CH_SORT_MTA) {
  1565.             mlp -> error_count = 0;
  1566.             if (mlp -> cache.cachetime < current_time)
  1567.                 cache_inc (&mlp -> cache, cache_time * 3 / 2);
  1568.             PP_NOTICE (("Avoiding MTA %s - too many errors",
  1569.                     mlp -> mtaname));
  1570.         }
  1571.         else if (mlp -> mta_enabled &&
  1572.             mlp -> cache.cachetime <= current_time &&
  1573.             (ml = findnextml (mlp, current_time, lock)) != NULL)
  1574.             return ml;
  1575.         mlp -> nactive --;
  1576.     }
  1577.  
  1578.     if (samemta) {
  1579.         *mlpp = NULL;
  1580.         return (Mlist *)0;
  1581.     }
  1582.  
  1583.     if (*mlpp) {
  1584.         PP_TRACE (("nothing on current MTA list - trying others"));
  1585.         *mlpp = NULLMTALIST;
  1586.     }
  1587.  
  1588.     for (mlp = clp -> mtas -> mta_forw; mlp != clp -> mtas;
  1589.          mlp = mlp -> mta_forw) {
  1590.         if (mlp -> mta_changed) {
  1591.             investigate_mta (mlp, current_time);
  1592.             mlp -> mta_changed = 0;
  1593.         }
  1594.         if (! mtaready (mlp)) {
  1595.             PP_TRACE (("mta %s not ready", mlp -> mtaname));
  1596.             continue;
  1597.         }
  1598.  
  1599.         if (mlp -> cache.cachetime > current_time) {
  1600.             PP_TRACE (("Mta %s cached for %d seconds",
  1601.                    mlp -> mtaname,
  1602.                    mlp -> cache.cachetime - current_time));
  1603.             continue;
  1604.         }
  1605.  
  1606.         if ((ml = findnextml (mlp, current_time, lock)) != NULL) {
  1607.             if (lock)
  1608.                 mlp -> nactive ++;
  1609.             *mlpp = mlp;
  1610.             remque (mlp);
  1611.             insque (mlp, clp -> mtas);
  1612.             PP_TRACE (("Found a ml"));
  1613.             return ml;
  1614.         }
  1615.         PP_TRACE (("Mta %s no messages ready", mlp -> mtaname));
  1616.     }
  1617.     return (Mlist *)0;
  1618. }
  1619.  
  1620. static Mlist *findnextml (mlp, now, lock)
  1621. Mtalist    *mlp;
  1622. time_t    now;
  1623. int    lock;
  1624. {
  1625.     Mlist    *ml;
  1626.  
  1627.     PP_TRACE (("findnextml (mta=%s)", mlp -> mtaname));
  1628.  
  1629.     for (ml = mlp -> msgs -> ml_forw; ml != mlp -> msgs;
  1630.          ml = ml -> ml_forw) {
  1631.         if (!msgready (ml)) {
  1632.             PP_TRACE (("Message %s not ready", ml -> ms -> queid));
  1633.             continue;
  1634.         }
  1635.  
  1636.         if (msgiscached (ml, now)) {
  1637.             PP_TRACE (("Message %s cached", ml -> ms -> queid));
  1638.             continue;
  1639.         }
  1640.  
  1641.         if (ml -> ms -> defferedtime &&
  1642.             ml -> ms -> defferedtime > now) {
  1643.             PP_TRACE (("Message defered"));
  1644.             continue;
  1645.         }
  1646.  
  1647.         if (lock)
  1648.             ml -> ms -> m_locked = 1;
  1649.         return ml;
  1650.     }
  1651.     return (Mlist *)0;
  1652. }
  1653.  
  1654. void zapmsg (ms)
  1655. MsgStruct *ms;
  1656. {
  1657.     MsgStruct **mspp;
  1658.  
  1659.     PP_TRACE (("zapmsg (%s)", ms -> queid));
  1660.  
  1661.     mspp = &msg_hash[hash(ms -> queid, QUE_HASHSIZE)];
  1662.  
  1663.     for (; *mspp; mspp = &(*mspp) -> ms_forw)
  1664.         if (*mspp == ms) {
  1665.             *mspp = (*mspp) -> ms_forw;
  1666.             freems (ms);
  1667.             PP_TRACE (("Message zapped"));
  1668.             return;
  1669.         }
  1670.     PP_LOG (LLOG_EXCEPTIONS, ("Can't locate message"));
  1671. }
  1672.  
  1673.  
  1674. Mlist    *findmtamsg (mlp, qid)
  1675. Mtalist    *mlp;
  1676. char *qid;
  1677. {
  1678.     MsgStruct *ms;
  1679.     Mlist    *ml;
  1680.  
  1681.     ms = find_msg (qid);
  1682.  
  1683.     for (ml = mlp -> msgs -> ml_forw; ml != mlp -> msgs;
  1684.          ml = ml -> ml_forw)
  1685.         if (ml -> ms == ms)
  1686.             return ml;
  1687.     return NULL;
  1688. }
  1689.  
  1690. MsgStruct *find_msg (qid)
  1691. char *qid;
  1692. {
  1693.     MsgStruct    *ms;
  1694.  
  1695.     PP_TRACE (("find_msg (%s)", qid));
  1696.     for (ms = msg_hash[hash (qid, QUE_HASHSIZE)]; ms; ms = ms -> ms_forw)
  1697.         if ( strcmp (ms -> queid, qid) == 0)
  1698.             return ms;
  1699.     return NULLMS;
  1700. }
  1701.  
  1702. /* ARGSUSED */
  1703. void kill_msg (ms)
  1704. MsgStruct *ms;
  1705. {
  1706.     PP_TRACE (("kill_msg"));
  1707. }
  1708.  
  1709. static int filtermatch (f, ms)
  1710. Filter *f;
  1711. MsgStruct *ms;
  1712. {
  1713.     PP_TRACE (("filtermatch ()"));
  1714.  
  1715.     if (f == NULLFL)
  1716.         return 0;
  1717.  
  1718.     if (f -> cont) {
  1719.         if (lexequ (f -> cont, ms -> contenttype) != 0)
  1720.             return filtermatch (f -> next, ms);
  1721.     }
  1722.  
  1723.     if (f -> eit) {
  1724.         LIST_BPT *bp, *bp2;
  1725.  
  1726.         for (bp = ms -> eit; bp; bp = bp -> li_next) {
  1727.             for (bp2 = f -> eit; bp2; bp2 = bp2 -> li_next) {
  1728.                 if (lexequ (bp -> li_name,
  1729.                         bp2 -> li_name) != 0)
  1730.                     return filtermatch (f -> next, ms);
  1731.             }
  1732.         }
  1733.     }
  1734.  
  1735.     if (f -> orig) {
  1736.         if (lexequ (f -> orig, ms -> originator) != 0)
  1737.             return filtermatch (f -> next, ms);
  1738.     }
  1739.     
  1740.     if (f -> recip) {
  1741.         Reciplist *rl, *rl0;
  1742.  
  1743.         for (rl0 = ms -> recips; rl0; rl0 = rl0 -> rp_next)
  1744.             if (rl0 -> id == 0)
  1745.                 break;
  1746.  
  1747.         for (rl = ms -> recips; rl; rl = rl -> rp_next) {
  1748.             switch (rl -> status) {
  1749.                 case ST_DELETE:
  1750.                 continue; /* we ignore recips that dead */
  1751.  
  1752.                 case ST_TIMEOUT:
  1753.                 case ST_WARNING:
  1754.                 case ST_NORMAL:
  1755.                 if (rl -> id == 0)
  1756.                     continue;
  1757.                 if (lexequ (rl -> user, f -> recip) == 0)
  1758.                     break;
  1759.                 continue;
  1760.  
  1761.                 case ST_DR:
  1762.                 if (rl0 &&
  1763.                     lexequ (rl0 -> user, f -> recip) == 0)
  1764.                     break;
  1765.                 continue;
  1766.                 default:
  1767.                 PP_LOG (LLOG_EXCEPTIONS,
  1768.                     ("filtermatch - Unknown state %d",
  1769.                      rl -> status));
  1770.                 continue;
  1771.             }
  1772.             break;
  1773.         }
  1774.         if (rl == NULLRL)
  1775.             return filtermatch (f -> next, ms);
  1776.     }
  1777.     if (f -> channel) {
  1778.         Reciplist *rl, *rl0;
  1779.  
  1780.         for (rl0 = ms -> recips; rl0; rl0 = rl0 -> rp_next)
  1781.             if (rl0 -> id == 0)
  1782.                 break;
  1783.         if (rl0 == NULLRL)
  1784.             return filtermatch (f -> next, ms);
  1785.  
  1786.         for (rl = ms -> recips; rl; rl = rl -> rp_next) {
  1787.             switch (rl -> status) {
  1788.                 case ST_DR:
  1789.                 if (f -> channel == rl0 -> chans -> li_chan)
  1790.                     break;
  1791.                 continue;
  1792.  
  1793.                 case ST_DELETE:
  1794.                 if (f -> channel == delete_chan -> chan)
  1795.                     break;
  1796.                 continue;
  1797.  
  1798.                 case ST_TIMEOUT:
  1799.                 if (f -> channel == timeout_chan -> chan)
  1800.                     break;
  1801.                 continue;
  1802.  
  1803.                 case ST_WARNING:
  1804.                 if (warn_chan &&
  1805.                     f -> channel == warn_chan -> chan)
  1806.                     break;
  1807.                 continue;
  1808.  
  1809.                 case ST_NORMAL:
  1810.                 if (rl -> cchan &&
  1811.                     f -> channel == rl -> cchan -> li_chan)
  1812.                     break;
  1813.                 continue;
  1814.                 default:
  1815.                 PP_LOG (LLOG_EXCEPTIONS,
  1816.                     ("filtermatch - unknown state %d",
  1817.                      rl -> status));
  1818.                 break;
  1819.             }
  1820.         }
  1821.         if (rl == NULLRL)
  1822.             return filtermatch (f -> next, ms);
  1823.     }
  1824.  
  1825.     if (f -> mta) {
  1826.         Reciplist *rl;
  1827.  
  1828.         for (rl = ms -> recips; rl; rl = rl -> rp_next) {
  1829.             switch (rl -> status) {
  1830.                 case ST_DR:
  1831.                 case ST_NORMAL:
  1832.                 if (lexequ (rl -> mta, f -> mta) == 0)
  1833.                     break;
  1834.                 if (rl -> ml && rl -> ml -> mlp &&
  1835.                     lexequ (rl -> ml -> mlp -> mtaname,
  1836.                         f -> mta) == 0)
  1837.                     break;
  1838.                 continue;
  1839.  
  1840.                 case ST_DELETE:
  1841.                 if (delete_chan &&
  1842.                     lexequ (f -> mta,
  1843.                         delete_chan -> channame) == 0)
  1844.                     break;
  1845.                 continue;
  1846.                 case ST_TIMEOUT:
  1847.                 if (timeout_chan &&
  1848.                     lexequ (f -> mta,
  1849.                         timeout_chan -> channame) == 0)
  1850.                     break;
  1851.                 continue;
  1852.                 case ST_WARNING:
  1853.                 if (warn_chan &&
  1854.                     lexequ (f -> mta,
  1855.                         warn_chan -> channame) == 0)
  1856.                     break;
  1857.                 continue;
  1858.                 default:
  1859.                 PP_LOG (LLOG_EXCEPTIONS,
  1860.                     ("filtermatch - Bad state %d", rl -> status));
  1861.                 continue;
  1862.             }
  1863.             break;
  1864.         }
  1865.         if (rl == NULLRL)
  1866.             return filtermatch (f -> next, ms);
  1867.     }
  1868.  
  1869.     if (f -> queid) {
  1870.         if (lexequ (f -> queid, ms -> queid) != 0)
  1871.             return filtermatch (f -> next, ms);
  1872.     }
  1873.  
  1874.     if (f -> mpduid) {
  1875.         if (!compmpduid (f -> mpduid, ms -> mpduid))
  1876.             return filtermatch (f -> next, ms);
  1877.     }
  1878.     if (f -> uacontent) {
  1879.         if (lexequ (f -> uacontent, ms -> uacontent) != 0)
  1880.             return filtermatch (f -> next, ms);
  1881.     }
  1882.     if (f ->morerecent) {
  1883.         if (ms -> age <= f -> morerecent)
  1884.             return filtermatch (f -> next, ms);
  1885.     }
  1886.     if (f -> earlier) {
  1887.         if (ms -> age >= f -> earlier)
  1888.             return filtermatch (f -> next, ms);
  1889.     }
  1890.     if (f -> priority != -1) {
  1891.         if (ms -> priority != f -> priority)
  1892.             return filtermatch (f -> next, ms);
  1893.     }
  1894.     if (f -> maxsize) {
  1895.         if (ms -> size > f -> maxsize)
  1896.             return filtermatch (f -> next, ms);
  1897.  
  1898.     }
  1899.     return 1;
  1900. }
  1901.  
  1902. static int compmpduid (m1, m2)
  1903. MPDUid *m1, *m2;
  1904. {
  1905.     PP_TRACE (("compmpduid ()"));
  1906.  
  1907.     if (!nullstrcmp (m1 -> mpduid_string, m2 -> mpduid_string))
  1908.         return 0;
  1909.  
  1910.     if (!nullstrcmp (m1 -> mpduid_DomId.global_Country,
  1911.              m2 -> mpduid_DomId.global_Country))
  1912.         return 0;
  1913.     if (!nullstrcmp (m1 -> mpduid_DomId.global_Admin,
  1914.              m2 -> mpduid_DomId.global_Admin))
  1915.         return 0;
  1916.     if (!nullstrcmp (m1 -> mpduid_DomId.global_Private,
  1917.              m2 -> mpduid_DomId.global_Private))
  1918.         return 0;
  1919.     return 1;
  1920. }
  1921.  
  1922. static int nullstrcmp (s1, s2)
  1923. char    *s1, *s2;
  1924. {
  1925.     if (s1 && s2)
  1926.         return lexequ (s1, s2) == 0;
  1927.     if (s1 == NULLCP && s2 == NULLCP)
  1928.         return 1;
  1929.     return 0;
  1930. }
  1931.  
  1932. int mtaready (mlp)
  1933. Mtalist *mlp;
  1934. {
  1935.     if (mlp -> nactive > 0) {
  1936.         PP_TRACE (("mta %s started already",
  1937.                mlp -> mtaname));
  1938.         return FALSE;
  1939.     }
  1940.     if (mlp -> mta_enabled == 0) {
  1941.         PP_TRACE (("Mta %s not enabled",
  1942.                mlp -> mtaname));
  1943.         return FALSE;
  1944.     }
  1945.     return TRUE;
  1946. }
  1947.  
  1948. msgready (ml)
  1949. Mlist    *ml;
  1950. {
  1951.     Reciplist **rl;
  1952.  
  1953.     if (ml -> ms -> m_locked) {
  1954.         PP_TRACE (("Message locked"));
  1955.         return FALSE;
  1956.     }
  1957.     for (rl = ml -> recips; rl < &ml -> recips[ml->rcount]; rl ++) {
  1958.         if ((*rl) -> msg_enabled == 0) {
  1959.             PP_TRACE (("Message disabled"));
  1960.             return FALSE;
  1961.         }
  1962.     }
  1963.         
  1964.     return TRUE;
  1965. }
  1966.  
  1967. msgiscached (ml, now)
  1968. Mlist *ml;
  1969. time_t now;
  1970. {
  1971.     Reciplist **rl;
  1972.  
  1973.     for (rl = ml -> recips; rl < &ml -> recips[ml->rcount]; rl ++) {
  1974.         if ((*rl) -> cache.cachetime <= now)
  1975.             return FALSE;
  1976.     }
  1977.     return TRUE;
  1978. }
  1979.  
  1980. void clear_msgcache (ml)
  1981. Mlist *ml;
  1982. {
  1983.     Reciplist **rl;
  1984.  
  1985.     for (rl = ml -> recips; rl < &ml -> recips[ml->rcount]; rl ++) {
  1986.         cache_clear (&(*rl) -> cache);
  1987.     }
  1988. }
  1989.  
  1990. void msgcache_inc (ml, plus)
  1991. Mlist *ml;
  1992. time_t plus;
  1993. {
  1994.     Reciplist **rl;
  1995.  
  1996.     for (rl = ml -> recips; rl < &ml -> recips[ml->rcount]; rl ++) {
  1997.         cache_inc (&(*rl) -> cache, plus);
  1998.     }
  1999. }
  2000.  
  2001. time_t msgmincache (ml)
  2002. Mlist *ml;
  2003. {
  2004.     time_t minc = 0;
  2005.     int    flag = 0;
  2006.     Reciplist **rl;
  2007.  
  2008.     for (rl = ml -> recips; rl < &ml -> recips[ml->rcount]; rl ++) {
  2009.         if (!flag) {
  2010.             flag = 1;
  2011.             minc = (*rl) -> cache.cachetime;
  2012.         }
  2013.         else
  2014.             minc = minc < (*rl) -> cache.cachetime ? minc :
  2015.                 (*rl) -> cache.cachetime;
  2016.     }
  2017.     return minc;
  2018. }
  2019.  
  2020. msg_unlock (ms)
  2021. MsgStruct *ms;
  2022. {
  2023.     Reciplist *rlp;
  2024.     Chanlist *clp;
  2025.     Mtalist *mlp;
  2026.     Mlist *ml;
  2027.  
  2028.     PP_TRACE (("msg_unlock"));
  2029.     ms -> m_locked = 0;
  2030.  
  2031.     for (rlp = ms -> recips; rlp; rlp = rlp -> rp_next) {
  2032.  
  2033.         if (rlp -> id == 0 ||
  2034.             rlp -> msg_enabled == 0)
  2035.             continue;
  2036.  
  2037.         if ((ml = rlp -> ml) == NULLMLIST) {
  2038.             PP_TRACE (("recipient not on mlist!"));
  2039.             continue;
  2040.         }
  2041.  
  2042.         if ((mlp = ml -> mlp) == NULLMTALIST) {
  2043.             PP_LOG (LLOG_EXCEPTIONS, ("message not on MTA"));
  2044.             continue;
  2045.         }
  2046.  
  2047.  
  2048.         if (current_time > rlp -> cache.cachetime)
  2049.             rlp -> cache.cachetime = current_time;
  2050.         if (ml -> ms -> defferedtime > rlp -> cache.cachetime)
  2051.             rlp -> cache.cachetime = ml -> ms -> defferedtime;
  2052.  
  2053.         if (rlp -> cache.cachetime < mlp -> nextevent &&
  2054.             mlp -> cache.cachetime < current_time)
  2055.             mlp -> nextevent = rlp -> cache.cachetime;
  2056.  
  2057.         if ((clp = mlp -> clp) == NULLCHANLIST) {
  2058.             PP_LOG (LLOG_EXCEPTIONS, ("mta not on channel!"));
  2059.             continue;
  2060.         }
  2061.         if (clp -> chan_enabled == 0)
  2062.             continue;
  2063.         if (rlp -> cache.cachetime < clp -> nextevent &&
  2064.             clp -> cache.cachetime < current_time)
  2065.             clp -> nextevent = rlp -> cache.cachetime;
  2066.     }
  2067. }
  2068.  
  2069. char    *chan2mta (chan, rlp)
  2070. CHAN *chan;
  2071. Reciplist *rlp;
  2072. {
  2073.     if (chan -> ch_sort[0] == CH_SORT_NONE)
  2074.         return chan -> ch_name;
  2075.     else if (chan -> ch_sort[0] == CH_SORT_USR)
  2076.         return rlp -> user;
  2077. /* removed for JA@UCL
  2078.     else    if (chan -> ch_mta)
  2079.         return chan -> ch_mta;
  2080. */
  2081.     else
  2082.         return rlp -> mta;
  2083. }
  2084.