home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / limit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-31  |  13.3 KB  |  437 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: limit.c,v 5.3 1993/05/31 19:17:02 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.3 $   $State: Exp $
  6.  *
  7.  *            Copyright (c) 1988-1992 USENET Community Trust
  8.  *            Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: limit.c,v $
  17.  * Revision 5.3  1993/05/31  19:17:02  syd
  18.  * While looking into the feasibility of adding `limit sender' as requested
  19.  * on Usenet, I noticed that the limit code was replicated for each of
  20.  * the supported conditions.  The following patch simplifies limit_selection()
  21.  * by sharing the common code between all conditions.
  22.  * From: chip@chinacat.unicom.com (Chip Rosenthal)
  23.  *
  24.  * Revision 5.2  1992/12/24  21:42:01  syd
  25.  * Fix messages and nls messages to match.  Plus use want_to
  26.  * where appropriate.
  27.  * From: Syd, via prompting from Jan Djarv <Jan.Djarv@sa.erisoft.se>
  28.  *
  29.  * Revision 5.1  1992/10/03  22:58:40  syd
  30.  * Initial checkin as of 2.4 Release at PL0
  31.  *
  32.  *
  33.  ******************************************************************************/
  34.  
  35. /** This stuff is inspired by MH and dmail and is used to 'select'
  36.     a subset of the existing mail in the folder based on one of a
  37.     number of criteria.  The basic tricks are pretty easy - we have
  38.     as status of VISIBLE associated with each header stored in the
  39.     (er) mind of the computer (!) and simply modify the commands to
  40.     check that flag...the global variable `selected' is set to the
  41.     number of messages currently selected, or ZERO if no select.
  42. **/
  43.  
  44. #include "headers.h"
  45. #include "s_elm.h"
  46. #include "s_aliases.h"
  47.  
  48. #define TO        1
  49. #define FROM        2
  50.  
  51. char *shift_lower();
  52.  
  53. int
  54. limit()
  55. {
  56.     /** returns non-zero if we changed selection criteria = need redraw **/
  57.     
  58.     char criteria[STRING], first[STRING], rest[STRING], msg[STRING];
  59.     static char *prompt = NULL;
  60.     int  last_selected, all;
  61.  
  62.     last_selected = selected;
  63.     all = 0;
  64.     if (prompt == NULL) {
  65.       prompt = catgets(elm_msg_cat, ElmSet, ElmLimitEnterCriteria,
  66.         "Enter criteria or '?' for help: ");
  67.     }
  68.  
  69.     if (selected) {
  70.       MCsprintf(msg, catgets(elm_msg_cat, ElmSet, ElmLimitAlreadyHave,
  71.         "Already have selection criteria - add more? (%c/%c) %c%c"),
  72.         *def_ans_yes, *def_ans_no, *def_ans_no, BACKSPACE);
  73.       PutLine0(LINES-2, 0, msg);
  74.       criteria[0] = ReadCh();
  75.       if (tolower(criteria[0]) == *def_ans_yes) {
  76.         Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmYesWord, "Yes."), 0);
  77.         PutLine0(LINES-3, COLUMNS-30, catgets(elm_msg_cat, ElmSet, ElmLimitAdding,
  78.         "Adding criteria..."));
  79.       } else {
  80.         Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmNoWord, "No."), 0);
  81.         selected = 0;
  82.         PutLine0(LINES-3, COLUMNS-30, catgets(elm_msg_cat, ElmSet, ElmLimitChanging,
  83.         "Change criteria..."));
  84.       }
  85.     }
  86.  
  87.     while(1) {
  88.       PutLine1(LINES-2, 0, prompt);
  89.       CleartoEOLN();
  90.  
  91.       criteria[0] = '\0';
  92.       optionally_enter(criteria, LINES-2, strlen(prompt), FALSE, FALSE);
  93.       error("");
  94.       
  95.       if (strlen(criteria) == 0) {
  96.         /* no change */
  97.         selected = last_selected;
  98.         return(FALSE);    
  99.       }
  100.  
  101.       split_word(criteria, first, rest);
  102.  
  103.       if (inalias) {
  104.         if (equal(first, "?")) {
  105.           if (last_selected)
  106.             error(catgets(elm_msg_cat, AliasesSet, AliasesEnterLastSelected,
  107.               "Enter:{\"name\",\"alias\"} [pattern] OR {\"person\",\"group\",\"user\",\"system\"} OR \"all\""));
  108.           else
  109.             error(catgets(elm_msg_cat, AliasesSet, AliasesEnterSelected,
  110.               "Enter: {\"name\",\"alias\"} [pattern] OR {\"person\",\"group\",\"user\",\"system\"}"));
  111.           continue;
  112.         }
  113.         else if (equal(first, "all")) {
  114.           all++;
  115.           selected = 0;
  116.         }
  117.         else if (equal(first, "name"))
  118.           selected = limit_alias_selection(BY_NAME, rest, selected);
  119.         else if (equal(first, "alias"))
  120.           selected = limit_alias_selection(BY_ALIAS, rest, selected);
  121.         else if (equal(first, "person"))
  122.           selected = limit_alias_selection(PERSON, rest, selected);
  123.         else if (equal(first, "group"))
  124.           selected = limit_alias_selection(GROUP, rest, selected);
  125.         else if (equal(first, "user"))
  126.           selected = limit_alias_selection(USER, rest, selected);
  127.         else if (equal(first, "system"))
  128.           selected = limit_alias_selection(SYSTEM, rest, selected);
  129.         else {
  130.           error1(catgets(elm_msg_cat, ElmSet, ElmLimitNotValidCriterion,
  131.         "\"%s\" not a valid criterion."), first);
  132.           continue;
  133.         }
  134.         break;
  135.       }
  136.       else {
  137.         if (equal(first, "?")) {
  138.           if (last_selected)
  139.             error(catgets(elm_msg_cat, ElmSet, ElmEnterLastSelected,
  140.               "Enter: {\"subject\",\"to\",\"from\"} [pattern] OR \"all\""));
  141.           else
  142.             error(catgets(elm_msg_cat, ElmSet, ElmEnterSelected,
  143.           "Enter: {\"subject\",\"to\",\"from\"} [pattern]"));
  144.           continue;
  145.         }
  146.         else if (equal(first, "all")) {
  147.           all++;
  148.           selected = 0;
  149.         }
  150.         else if (equal(first, "subj") || equal(first, "subject"))
  151.           selected = limit_selection(SUBJECT, rest, selected);
  152.         else if (equal(first, "to"))
  153.           selected = limit_selection(TO, rest, selected);
  154.         else if (equal(first, "from"))
  155.           selected = limit_selection(FROM, rest, selected);
  156.         else {
  157.           error1(catgets(elm_msg_cat, ElmSet, ElmLimitNotValidCriterion,
  158.         "\"%s\" not a valid criterion."), first);
  159.           continue;
  160.         }
  161.         break;
  162.       }
  163.     }
  164.  
  165.     if (all && last_selected)
  166.       strcpy(msg, catgets(elm_msg_cat, ElmSet, ElmLimitReturnToUnlimited,
  167.         "Returned to unlimited display."));
  168.     else {
  169.       if (inalias) {
  170.         if (selected > 1)
  171.           sprintf(msg, catgets(elm_msg_cat, AliasesSet,
  172.         AliasesLimitMessagesSelected, "%d aliases selected."),
  173.         selected);
  174.         else if (selected == 1)
  175.           strcpy(msg, catgets(elm_msg_cat, AliasesSet,
  176.         AliasesLimitMessageSelected, "1 alias selected."));
  177.         else
  178.           strcpy(msg, catgets(elm_msg_cat, AliasesSet,
  179.         AliasesLimitNoMessagesSelected, "No aliases selected."));
  180.       }
  181.       else {
  182.         if (selected > 1)
  183.           sprintf(msg, catgets(elm_msg_cat, ElmSet,
  184.         ElmLimitMessagesSelected, "%d messages selected."), selected);
  185.         else if (selected == 1)
  186.           strcpy(msg, catgets(elm_msg_cat, ElmSet, ElmLimitMessageSelected,
  187.         "1 message selected."));
  188.         else
  189.           strcpy(msg, catgets(elm_msg_cat, ElmSet,
  190.         ElmLimitNoMessagesSelected, "No messages selected."));
  191.       }
  192.     }
  193.     set_error(msg);
  194.  
  195.     /* we need a redraw if there had been a selection or there is now. */
  196.     if (last_selected || selected) {
  197.       /* if current message won't be on new display, go to first message */
  198.       if (selected && !(ifmain(headers[current-1]->status,
  199.                                aliases[current-1]->status) & VISIBLE))
  200.         current = visible_to_index(1)+1;
  201.       return(TRUE);
  202.     } else {
  203.       return(FALSE);
  204.     }
  205. }
  206.  
  207. int
  208. limit_selection(based_on, pattern, additional_criteria)
  209. int based_on, additional_criteria;
  210. char *pattern;
  211. {
  212.     /** Given the type of criteria, and the pattern, mark all
  213.         non-matching headers as ! VISIBLE.  If additional_criteria,
  214.         don't mark as visible something that isn't currently!
  215.     **/
  216.  
  217.     register int iindex;
  218.     register char *hdr_value;
  219.     int count = 0;
  220.  
  221.     dprint(2, (debugfile, "\n\n\n**limit on %d - '%s' - (%s) **\n\n",
  222.            based_on, pattern, additional_criteria?"add'tl":"base"));
  223.  
  224.     for (iindex = 0 ; iindex < message_count ; iindex++) {
  225.  
  226.         switch (based_on) {
  227.         case FROM:
  228.         hdr_value = headers[iindex]->from;
  229.         break;
  230.         case TO:
  231.         hdr_value = headers[iindex]->to;
  232.         break;
  233.         case SUBJECT:
  234.         default:
  235.         hdr_value = headers[iindex]->subject;
  236.         break;
  237.         }
  238.  
  239.         if (!in_string(shift_lower(hdr_value), pattern))
  240.         headers[iindex]->status &= ~VISIBLE;
  241.         else if (additional_criteria && !(headers[iindex]->status&VISIBLE))
  242.         ; /* leave this marked not visible */
  243.         else {
  244.         headers[iindex]->status |= VISIBLE;
  245.         count++;
  246.         dprint(5, (debugfile,
  247.             "  Message %d (%s from %s) marked as visible\n",
  248.             iindex, headers[iindex]->subject, headers[iindex]->from));
  249.         }
  250.  
  251.     }
  252.  
  253.     dprint(4, (debugfile, "\n** returning %d selected **\n\n\n", count));
  254.     return(count);
  255. }
  256.  
  257. int
  258. limit_alias_selection(based_on, pattern, additional_criteria)
  259. int based_on, additional_criteria;
  260. char *pattern;
  261. {
  262.     /** Given the type of criteria, and the pattern, mark all
  263.         non-matching aliases as ! VISIBLE.  If additional_criteria,
  264.         don't mark as visible something that isn't currently!
  265.     **/
  266.  
  267.     register int iindex, count = 0;
  268.  
  269.     dprint(2, (debugfile, "\n\n\n**limit on %d - '%s' - (%s) **\n\n",
  270.            based_on, pattern, additional_criteria?"add'tl":"base"));
  271.  
  272.     if (based_on == BY_NAME) {
  273.       for (iindex = 0; iindex < message_count; iindex++)
  274.         if (! in_string(shift_lower(aliases[iindex]->name), pattern))
  275.           clearit(aliases[iindex]->status, VISIBLE);
  276.         else if (additional_criteria &&     
  277.              !(aliases[iindex]->status & VISIBLE))
  278.           clearit(aliases[iindex]->status, VISIBLE);    /* shut down! */
  279.         else { /* mark it as readable */
  280.           setit(aliases[iindex]->status, VISIBLE);
  281.           count++;
  282.           dprint(5, (debugfile,
  283.              "  Alias %d (%s, %s) marked as visible\n",
  284.             iindex, aliases[iindex]->alias,
  285.             aliases[iindex]->name));
  286.         }
  287.     }
  288.     else if (based_on == BY_ALIAS) {
  289.       for (iindex = 0; iindex < message_count; iindex++)
  290.         if (! in_string(shift_lower(aliases[iindex]->alias), pattern))
  291.           clearit(aliases[iindex]->status, VISIBLE);
  292.         else if (additional_criteria &&     
  293.              !(aliases[iindex]->status & VISIBLE))
  294.           clearit(aliases[iindex]->status, VISIBLE);    /* shut down! */
  295.         else { /* mark it as readable */
  296.           setit(aliases[iindex]->status, VISIBLE);
  297.           count++;
  298.           dprint(5, (debugfile, 
  299.             "  Alias %d (%s, %s) marked as visible\n",
  300.             iindex, aliases[iindex]->alias,
  301.             aliases[iindex]->name));
  302.         }
  303.     }
  304.     else {
  305.       for (iindex = 0; iindex < message_count; iindex++)
  306.         if (! (based_on & aliases[iindex]->type))
  307.           clearit(aliases[iindex]->status, VISIBLE);
  308.         else if (additional_criteria &&     
  309.              !(aliases[iindex]->status & VISIBLE))
  310.           clearit(aliases[iindex]->status, VISIBLE);    /* shut down! */
  311.         else { /* mark it as readable */
  312.           setit(aliases[iindex]->status, VISIBLE);
  313.           count++;
  314.           dprint(5, (debugfile,
  315.             "  Alias %d (%s, %s) marked as visible\n",
  316.             iindex, aliases[iindex]->alias,
  317.             aliases[iindex]->name));
  318.         }
  319.     }
  320.  
  321.     dprint(4, (debugfile, "\n** returning %d selected **\n\n\n", count));
  322.  
  323.     return(count);
  324. }
  325.  
  326. int
  327. next_message(iindex, skipdel)
  328. register int iindex, skipdel;
  329. {
  330.     /** Given 'iindex', this routine will return the actual iindex into the
  331.         array of the NEXT message, or '-1' iindex is the last.
  332.         If skipdel, return the iindex for the NEXT undeleted message.
  333.         If selected, return the iindex for the NEXT message marked VISIBLE.
  334.     **/
  335.  
  336.     register int remember_for_debug, stat;
  337.  
  338.     if (iindex < 0) return(-1);    /* invalid argument value! */
  339.  
  340.     remember_for_debug = iindex;
  341.  
  342.     for(iindex++;iindex < message_count; iindex++) {
  343.       stat = ifmain(headers[iindex]->status, aliases[iindex]->status);
  344.       if (((stat & VISIBLE) || (!selected))
  345.         && (!(stat & DELETED) || (!skipdel))) {
  346.           dprint(9, (debugfile, "[Next%s%s: given %d returning %d]\n", 
  347.           (skipdel ? " undeleted" : ""),
  348.           (selected ? " visible" : ""),
  349.           remember_for_debug+1, iindex+1));
  350.           return(iindex);
  351.       }
  352.     }
  353.     return(-1);
  354. }
  355.  
  356. int
  357. prev_message(iindex, skipdel)
  358. register int iindex, skipdel;
  359. {
  360.     /** Like next_message, but the PREVIOUS message. **/
  361.  
  362.     register int remember_for_debug, stat;
  363.  
  364.     if (iindex >= message_count) return(-1);    /* invalid argument value! */
  365.  
  366.     remember_for_debug = iindex;
  367.     for(iindex--; iindex >= 0; iindex--) {
  368.       stat = ifmain(headers[iindex]->status, aliases[iindex]->status);
  369.       if (((stat & VISIBLE) || (!selected))
  370.         && (!(stat & DELETED) || (!skipdel))) {
  371.           dprint(9, (debugfile, "[Previous%s%s: given %d returning %d]\n", 
  372.           (skipdel ? " undeleted" : ""),
  373.           (selected ? " visible" : ""),
  374.           remember_for_debug+1, iindex+1));
  375.           return(iindex);
  376.       }
  377.     }
  378.     return(-1);
  379. }
  380.  
  381.  
  382. int
  383. compute_visible(message)
  384. int message;
  385. {
  386.     /** return the 'virtual' iindex of the specified message in the
  387.         set of messages - that is, if we have the 25th message as
  388.         the current one, but it's #2 based on our limit criteria,
  389.         this routine, given 25, will return 2.
  390.     **/
  391.  
  392.     register int iindex, count = 0;
  393.  
  394.     if (! selected) return(message);
  395.  
  396.     if (message < 1) message = 1;    /* normalize */
  397.  
  398.     for (iindex = 0; iindex < message; iindex++)
  399.        if (ifmain(headers[iindex]->status,
  400.                   aliases[iindex]->status) & VISIBLE)
  401.          count++;
  402.  
  403.     dprint(4, (debugfile,
  404.         "[compute-visible: displayed message %d is actually %d]\n",
  405.         count, message));
  406.  
  407.     return(count);
  408. }
  409.  
  410. int
  411. visible_to_index(message)
  412. int message;
  413. {
  414.     /** Given a 'virtual' iindex, return a real one.  This is the
  415.         flip-side of the routine above, and returns (message_count+1)
  416.         if it cannot map the virtual iindex requested (too big) 
  417.     **/
  418.  
  419.     register int iindex = 0, count = 0;
  420.  
  421.     for (iindex = 0; iindex < message_count; iindex++) {
  422.        if (ifmain(headers[iindex]->status,
  423.                   aliases[iindex]->status) & VISIBLE)
  424.          count++;
  425.        if (count == message) {
  426.          dprint(4, (debugfile,
  427.              "visible-to-index: (up) index %d is displayed as %d\n",
  428.              message, iindex));
  429.          return(iindex);
  430.        }
  431.     }
  432.  
  433.     dprint(4, (debugfile, "index %d is NOT displayed!\n", message));
  434.  
  435.     return(message_count+1);
  436. }
  437.