Beispiel #1
0
    def testBothAppend(self):
        queue = Pending.Queue(dispose=self.dispose, verbose=verbose)
        queue.initQueue()

        queue.mainLoop()
        self.assertEqual(self.file_appends, self.expectedFileAppends())
        self.assertEqual(self.db_inserts, self.expectedDbInserts())
Beispiel #2
0
 def testInitQueueFromParams(self):
     # With a list provided, only those specific message IDs should be
     # present.
     pending = Pending.Queue(['11243439251.2345', '1303433207.12347'])
     pending.initQueue()
     self.assertEqual(pending.msgs,
                      ['11243439251.2345', '1303433207.12347'])
Beispiel #3
0
 def testInitQueueFromPending(self):
     # With no arguments, everything from the pending queue should be
     # included.
     pending = Pending.Queue()
     pending.initQueue()
     self.assertEqual(
         pending.msgs,
         ['1243439251.12345', '1303349951.12346', '1303433207.12347'])
Beispiel #4
0
    def testPretend(self):
        queue = Pending.Queue(dispose=self.dispose,
                              verbose=verbose,
                              pretend=True)
        queue.initQueue()

        queue.mainLoop()
        self.assertEqual(self.file_appends, [])
        self.assertEqual(self.db_inserts, [])
Beispiel #5
0
def ReleaseAndDelete(Threshold):
  "Release all messages younger than given amount.  Delete rest."

  from TMDA import Defaults
  from TMDA import Pending

  # Release
  Pending.Queue(dispose = "release", threshold = Threshold, younger = 1,
    verbose = 0).initQueue().mainLoop()

  # Wait for messages to release...
  while 1:
    time.sleep(1)
    Queue = Pending.Queue(threshold = Threshold, younger = 1)
    Queue.initQueue()
    Msgs = 0
    for MsgID in Queue.listPendingIds():
      Msgs += Queue.checkTreshold(MsgID)
    if not Msgs: break

  # Delete
  Pending.Queue(dispose = "delete", verbose = 0).initQueue().mainLoop()

  # Tidy-up
  Dir = CgiUtil.ExpandUser(Defaults.RESPONSE_DIR)
  for Filename in glob.glob(os.path.join(Dir, "*.*.*")):
    try:
      os.unlink(Filename)
    except OSError:
      pass
  try:
    os.rmdir(Dir)
  except OSError:
    pass
  Filename = CgiUtil.ExpandUser(Defaults.PENDING_CACHE)
  try:
    os.unlink(Filename)
  except OSError:
    pass
  Dir = os.path.join(Defaults.DATADIR, "pending")
  try:
    os.rmdir(Dir)
  except OSError:
    pass
Beispiel #6
0
    def testInitQueueFromStdin(self):
        saved_stdin = sys.stdin
        try:
            # With a '-', IDs should be read from stdin.
            sys.stdin = StringIO.StringIO(
                '1303349951.12346\n1243439251.12345\n')
            pending = Pending.Queue(['-'])
            pending.initQueue()
            self.assertEqual(pending.msgs,
                             ['1243439251.12345', '1303349951.12346'])

            # With a '-' in combo with IDs, should include both stdin and the
            # specified IDs.
            sys.stdin = StringIO.StringIO('1303349951.12346\n')
            pending = Pending.Queue(['-', '1303433207.12347'])
            pending.initQueue()
            self.assertEqual(pending.msgs,
                             ['1303349951.12346', '1303433207.12347'])
        finally:
            sys.stdin = saved_stdin
Beispiel #7
0
    def testThresholdOlder(self):
        threshold = "%ds" % (time.time() - 1280000000)

        queue = Pending.Queue(dispose=self.dispose,
                              verbose=verbose,
                              threshold=threshold,
                              older=True)
        queue.initQueue()

        queue.mainLoop()
        self.assertEqual(len(self.file_appends), 1)
        self.assertEqual(len(self.db_inserts), 1)
Beispiel #8
0
    def testCached(self):
        # First, cause some IDs to be cached.
        cache_ids = ['1243439251.12345', '1303433207.12347']
        queue = Pending.Queue(cache_ids,
                              cache=True,
                              dispose='pass',
                              verbose=verbose)
        queue.initQueue()

        queue.mainLoop()
        # Make sure the cached IDs are as expected.
        self.assertEqual(queue.msgcache, list(reversed(cache_ids)))

        # Revisit the loop, this time expected only the non-cached IDs to be
        # handled.
        queue = Pending.Queue(cache=True,
                              dispose=self.dispose,
                              verbose=verbose)
        queue.initQueue()

        queue.mainLoop()
        self.assertEqual(len(self.file_appends), 1)
        self.assertEqual(len(self.db_inserts), 1)
Beispiel #9
0
def Release(QueryString):
    """Release the message represented in the QueryString.

QueryString is in one of two formats, real users MAY confirm with:

<UID>.<confirm_cookie>

Virtual users MUST confirm with:

<UID>&<recipient_address>&<confirm_cookie>

Where <UID> is the UID of the TMDA account, <recipient_address> is the untagged
address of the original message recipient, and <confirm_cookie> is used to find
and validate the pending email in question."""

    # Prepare the traceback in case of uncaught exception
    MyCgiTb.ErrTemplate = "prog_err2.html"
    CgiUtil.ErrTemplate = "error2.html"

    try:
        UID, Recipient, Cookie = QueryString.split("&")
        UID = int(UID)
        OldStyle = 0

        # Get base address from Recipient
        RecipUser, RecipDomain = Recipient.split("@")
        User = RecipUser.split('-')[0] + "@" + RecipDomain
    except (ValueError, KeyError):
        try:
            # Check for old-style format
            UID, Cookie = QueryString.split(".", 1)
            UID = int(UID)
            User = pwd.getpwuid(UID)[0]
            OldStyle = 1
        except (ValueError, KeyError):
            CgiUtil.TermError(
                "Unable to parse query string.",
                "Program error / corrupted link.", "locate pending e-mail", "",
                """Please check the link you followed and
make sure that it is typed in exactly as it was sent to you.""")
    try:
        # Get real user from UID
        Timestamp, PID, HMAC = Cookie.split(".")
    except ValueError:
        CgiUtil.TermError(
            "Unable to parse query string.", "Program error / corrupted link.",
            "locate pending e-mail", "",
            """Please check the link you followed and
make sure that it is typed in exactly as it was sent to you.""")

    MsgID = "%s.%s.msg" % (Timestamp, PID)
    # Check to make sure they're not trying to access anything other than email
    if not re.compile("^\d+\.\d+\.msg$").search(MsgID):
        CgiUtil.TermError("<tt>%s.%s.%s</tt> is not a valid message ID." % \
          (Timestamp, PID, HMAC), "Program error / corrupted link.",
          "retrieve pending e-mail", "", """Please check the link you followed and
make sure that it is typed in exactly as it was sent to you.""")

    # Set up the user's home directory.
    try:
        os.seteuid(0)
        os.setegid(0)
        os.setuid(0)
    except OSError:
        pass
    try:
        if os.environ.has_key("TMDA_VLOOKUP") and not OldStyle:
            VLookup = \
              CgiUtil.ParseString(os.environ["TMDA_VLOOKUP"], User )
            List = Util.RunTask(VLookup[1:])
            Sandbox = {"User": User}
            Filename = os.path.join("stubs", "%s.py" % VLookup[0])
            try:
                execfile(Filename, Sandbox)
            except IOError:
                CgiUtil.TermError(
                    "Can't load virtual user stub.",
                    "Cannot execute %s" % Filename, "execute stub",
                    "TMDA_VLOOKUP = %s" % os.environ["TMDA_VLOOKUP"],
                    """Contact this message's sender by an alternate means and inform them
of this error, or try confirming your message using an alternate method.""")
            Home, UID, GID = Sandbox["getuserparams"](List)[0:3]
        else:
            Home, UID, GID = Util.getuserparams(pwd.getpwuid(UID)[0])
    except KeyError:
        CgiUtil.TermError(
            "No such user", "User %s not found" % User, "find user %s" % User,
            "",
            """Contact this message's sender by an alternate means and inform them
of this error, or try confirming your message using an alternate method.""")
    if UID < 2:
        PasswordRecord = pwd.getpwnam(os.environ["TMDA_VUSER"])
        UID = PasswordRecord[2]
        GID = PasswordRecord[3]
        if not int(UID):
            CgiUtil.TermError(
                "TMDA_VUSER is UID 0.", "It is not safe to run "
                "tmda-cgi as root.", "set euid",
                "TMDA_VUSER = %s" % os.environ["TMDA_VUSER"],
                """Contact this message's sender by an alternate means and inform them
of this error, or try confirming your message using an alternate method.""")

    # We now have the home directory and the User.  Set this in the environment.
    os.environ["USER"] = User
    os.environ["LOGNAME"] = User
    os.environ["HOME"] = Home

    # Is there a TMDARC variable?
    if os.environ.has_key("TMDARC"):
        # Yes, replace it
        os.environ["TMDARC"] = os.environ["TMDARC"].replace(
            "/~/", "/%s/" % User)

    # Try to change users
    try:
        os.seteuid(0)
        os.setegid(0)
        os.setgid(int(GID))
        os.setuid(int(UID))
    except OSError:
        pass

    # Now that we know who we are, get our defaults
    try:
        from TMDA import Defaults
    except Errors.ConfigError:
        CgiUtil.TermError(
            "Confirm Failed",
            "Old-style URL is not compatible with virtual users",
            "use incompatible URL", "", """Contact this message's sender by an
alternate means and inform them of this error, or try confirming your message
using an alternate method.""")
    from TMDA import Pending
    from TMDA import Cookie

    try:
        Defaults.CRYPT_KEY
    except AttributeError:
        CgiUtil.TermError(
            "Could not read CRYPT_KEY.",
            "CRYPT_KEY can not be read by group %d." % os.getegid(),
            "read CRYPT_KEY", "ALLOW_MODE_640 = %d<br>%s" %
            (Defaults.ALLOW_MODE_640,
             CgiUtil.FileDetails("Cryptography key", Defaults.CRYPT_KEY_FILE)),
            """Any of the following solutions:<br>
1. Place <tt>%s</tt> in any of the groups that user %d belongs to.<br>
2. Do all three of the following:<br>
&nbsp;&nbsp;&nbsp;&#8226; Place <tt>%s</tt> in group %d.<br>
&nbsp;&nbsp;&nbsp;&#8226; Assign permissions 640 to <tt>%s</tt>.<br>
&nbsp;&nbsp;&nbsp;&#8226; Set ALLOW_MODE_640 = 1 in your configuration file.<br>
3. Disable URL confirmation in your confirmation template.""" %
            (Defaults.CRYPT_KEY_FILE, os.geteuid(), Defaults.CRYPT_KEY_FILE,
             os.getegid(), Defaults.CRYPT_KEY_FILE))

    # Validate the HMAC
    if Cookie.confirmationmac(Timestamp, PID, "accept") != HMAC:
        CgiUtil.TermError("<tt>%s.%s.%s</tt> is not a valid message ID." % \
          (Timestamp, PID, HMAC), "Program error / corrupted link.",
          "retrieve pending e-mail", "",
          "Recheck link or contact TMDA programmers.")

    # Read in e-mail
    try:
        MsgObj = Pending.Message(MsgID)
    except Errors.MessageError:
        CgiUtil.TermError("Message could not be fetched.",
                          "Message has already been released or deleted.",
                          "retrieve pending e-mail", "",
                          "Inquire with recipient about e-mail.")

    T = Template.Template("released.html")

    # Fetch row
    Row = T["Row"]

    # Generate header rows
    for Header in Defaults.SUMMARY_HEADERS:
        T["Name"] = Header.capitalize()
        T["Value"] = CgiUtil.Escape(MsgObj.msgobj[Header])
        Row.Add()

    # Can we add this address to a do-not-confirm-again list?
    if Defaults.CONFIRM_APPEND:
        ConfirmAddr = Util.confirm_append_address \
        (
          parseaddr(MsgObj.msgobj["x-primary-address"])[1],
          parseaddr(MsgObj.msgobj["return-path"])[1]
        )
        if ConfirmAddr:
            Util.append_to_file(ConfirmAddr, Defaults.CONFIRM_APPEND)
            T["Address"] = ConfirmAddr
        else:
            T["Future"]
    else:
        T["Future"]

    print T

    # Make sure release does not write to PENDING_RELEASE_APPEND
    Defaults.PENDING_RELEASE_APPEND = None

    MsgObj.release()
Beispiel #10
0
def Show():
    "Show an e-mail in HTML."

    global Allow, Remove, Attachment, Divider, PartTemplate, T

    # Deal with a particular message?
    if Form.has_key("msgid"):
        PVars["MsgID"] = Form["msgid"].value
        PVars.Save()

    # Check to make sure they're not trying to access anything other than email
    if not re.compile("^\d+\.\d+\.msg$").search(PVars["MsgID"]):
        CgiUtil.TermError(
            "<tt>%s</tt> is not a valid message ID." % PVars["MsgID"],
            "Program error / corrupted link.", "retrieve pending e-mail", "",
            "Recheck link or contact TMDA programmers.")

    # Fetch the queue
    Queue = Pending.Queue(descending=1, cache=1)
    Queue.initQueue()
    Queue._loadCache()

    # Get e-mail template
    T = Template.Template("view.html")
    T["EmailClass"] = PVars[("ViewPending", "EmailClass")]

    # Locate messages in pending dir
    Msgs = Queue.listPendingIds()
    try:
        MsgIdx = Msgs.index(PVars["MsgID"])
    except ValueError:  # Oops.  Perhaps they released the message?  Get the list!
        raise Errors.MessageError

    # Any subcommands?
    if Form.has_key("subcmd"):

        # first/prev/next/last subcommands
        if Form["subcmd"].value == "first":
            MsgIdx = 0
            PVars["Pager"] = 0
        elif Form["subcmd"].value == "prev":
            if MsgIdx > 0:
                MsgIdx -= 1
                PVars["Pager"] -= 1
        elif Form["subcmd"].value == "next":
            if MsgIdx < (len(Msgs) - 1):
                MsgIdx += 1
                PVars["Pager"] += 1
        elif Form["subcmd"].value == "last":
            MsgIdx = len(Msgs) - 1
            PVars["Pager"] = len(Msgs)

        # Toggle headers?
        elif Form["subcmd"].value == "headers":
            if PVars[("ViewPending", "Headers")] == "short":
                PVars[("ViewPending", "Headers")] = "all"
            else:
                PVars[("ViewPending", "Headers")] = "short"

        else:
            # Read in e-mail
            try:
                MsgObj = Pending.Message(PVars["MsgID"])

                if Form["subcmd"].value == "pass": pass
                if Form["subcmd"].value == "delete":
                    MsgObj.delete()
                elif Form["subcmd"].value == "release":
                    MsgObj.release()
                    PVars["InProcess"][PVars["MsgID"]] = 1
                elif Form["subcmd"].value == "white":
                    MsgObj.whitelist()
                    MsgObj.release()
                    PVars["InProcess"][PVars["MsgID"]] = 1
                elif Form["subcmd"].value == "black":
                    MsgObj.blacklist()
                    MsgObj.delete()
                elif Form["subcmd"].value == "spamcop":
                    CgiUtil.ReportToSpamCop(MsgObj)
                    MsgObj.delete()
                # TODO: Check if subcmd is a custom filter and process accordingly
                del Msgs[MsgIdx]
            except IOError:
                pass

            # So which message are we on now?
            if len(Msgs) == 0:  # Oops! None left!
                PVars.Save()
                raise Errors.MessageError
            if MsgIdx >= len(Msgs):
                MsgIdx = len(Msgs) - 1
            PVars["MsgID"] = Msgs[MsgIdx]

        # Save session
        PVars.Save()

    # Get message ID
    T["MsgID"] = Msgs[MsgIdx]
    PVars["MsgID"] = Msgs[MsgIdx]

    # Grey out the first & prev buttons?
    if MsgIdx == 0:
        T["FirstButton1Active"]
        T["PrevButton1Active"]
        T["FirstButton2Active"]
        T["PrevButton2Active"]
    else:
        T["FirstButton1Inactive"]
        T["PrevButton1Inactive"]
        T["FirstButton2Inactive"]
        T["PrevButton2Inactive"]

    # Grey out the next & last buttons?
    if MsgIdx == (len(Msgs) - 1):
        T["NextButton1Active"]
        T["LastButton1Active"]
        T["NextButton2Active"]
        T["LastButton2Active"]
    else:
        T["NextButton1Inactive"]
        T["LastButton1Inactive"]
        T["NextButton2Inactive"]
        T["LastButton2Inactive"]

    # Use Javascript confirmation?
    if PVars[("General", "UseJSConfirm")] == "Yes":
        T["OnSubmit"] = "onSubmit=\"return TestConfirm()\""
        T["DeleteURL"] = "javascript:ConfirmDelete()"
        T["BlacklistURL"] = "javascript:ConfirmBlacklist()"
        T["SpamCopURL"] = "javascript:ConfirmSpamCop()"
    else:
        T["OnSubmit"] = ""
        T["DeleteURL"]    = "%s?cmd=view&subcmd=delete&SID=%s" % \
          (os.environ["SCRIPT_NAME"], PVars.SID)
        T["BlacklistURL"] = "%s?cmd=view&subcmd=black&SID=%s" % \
          (os.environ["SCRIPT_NAME"], PVars.SID)
        T["SpamCopURL"]   = "%s?cmd=view&subcmd=spamcop&SID=%s" % \
          (os.environ["SCRIPT_NAME"], PVars.SID)

    T["DispRange"] = "%d of %d" % (MsgIdx + 1, len(Msgs))

    # Read in e-mail
    MsgObj = Pending.Message(PVars["MsgID"])
    Queue._addCache(PVars["MsgID"])
    Queue._saveCache()

    # Extract header row
    HeaderRow = T["HeaderRow"]
    if PVars[("ViewPending", "Headers")] == "all":
        # Remove header table
        T["ShortHeaders"]

        # Generate all headers
        Headers = ""
        for Line in CgiUtil.Escape(MsgObj.show()).split("\n"):
            if Line == "": break
            # Decode internationalized headers
            for decoded in email.Header.decode_header(Line):
                Headers += decoded[0] + " "
                if decoded[1]:
                    cset = email.Charset.Charset(
                        decoded[1]).input_charset.split()
                    T["CharSet"] = cset[0]
            Headers += "\n"
        T["Headers"] = '<pre class="Headers">%s</pre>' % Headers
    else:
        # Remove all header block
        T["AllHeaders"]

        # Generate short headers
        for Header in Defaults.SUMMARY_HEADERS:
            T["Name"] = Header.capitalize()
            value = ""
            # Decode internationalazed headers
            for decoded in email.Header.decode_header(MsgObj.msgobj[Header]):
                value += decoded[0] + " "
                if decoded[1]:
                    cset = email.Charset.Charset(
                        decoded[1]).input_charset.split()
                    T["CharSet"] = cset[0]
            T["Value"] = CgiUtil.Escape(value)
            HeaderRow.Add()

    # Go through each part and generate HTML
    Allow = re.split("[,\s]+", PVars[("ViewPending", "AllowTags")])
    Remove = re.split("[,\s]+", PVars[("ViewPending", "BlockRemove")])
    Attachment = T["Attachment"]
    Divider = T["Divider"]
    PartTemplate = T["Part"]

    ShowPart(MsgObj.msgobj)

    # Remove unneeded bits?
    NumCols = int(T["NumCols"])

    # TODO: Programatically check a setting to see which are allowed,
    #       and which should be shown.
    # For now, allow and show everything
    RlAllowed = 1
    DlAllowed = 1
    WhAllowed = 1 and Defaults.PENDING_WHITELIST_APPEND
    BlAllowed = 1 and Defaults.PENDING_BLACKLIST_APPEND
    ScAllowed = 1 and PVars[("General", "SpamCopAddr")]
    FltAllowed = 1
    RlShow = RlAllowed and 1
    DlShow = DlAllowed and 1
    WhShow = WhAllowed and 1
    BlShow = BlAllowed and 1
    ScShow = ScAllowed and 1

    if not RlAllowed:
        T["RlAction"]
    if not RlShow:
        NumCols -= 1
        T["RlIcon1"]
        T["RlIcon2"]
    if not DlAllowed:
        T["DlAction"]
    if not DlShow:
        NumCols -= 1
        T["DlIcon1"]
        T["DlIcon2"]
    if not BlAllowed:
        T["BlAction"]
    if not BlShow:
        NumCols -= 1
        T["BlIcon1"]
        T["BlIcon2"]
    if not WhAllowed:
        T["WhAction"]
    if not WhShow:
        NumCols -= 1
        T["WhIcon1"]
        T["WhIcon2"]
    if not ScAllowed:
        T["ScAction"]
    if not ScShow:
        NumCols -= 1
        T["SCIcon1"]
        T["SCIcon2"]
    if FltAllowed:
        T["FilterOptions"] = CgiUtil.getFilterOptions()
    else:
        T["FilterOptions"] = ""

    T["NumCols"] = NumCols
    if len(Attachment.HTML) == 0:
        T["NoAttachments"]

    # Display HTML page with email included.
    print T
Beispiel #11
0
def Show():
    "Show all pending e-mail in an HTML form."

    ReadList = []
    if Form.has_key("subcmd"):
        # Batch operation
        if Form["subcmd"].value == "batch":
            ReleaseList = []
            WhiteList = []
            BlackList = []
            DeleteList = []
            OtherList = []
            OtherAction = "Pass"
            for Count in range(int(PVars[("PendingList", "PagerSize")])):
                # Check for radioboxes (a0 through a%(PagerSize)d)
                if Form.has_key("a%d" % Count):
                    # Check to make sure they're not trying to access anything other than
                    # email
                    if not GoodFN.search(Form["m%d" % Count].value):
                        CgiUtil.TermError(
                            "<tt>%s</tt> is not a valid message ID." %
                            Form["m%d" % Count].value,
                            "Program error / corrupted link.",
                            "process pending e-mail", "",
                            "Recheck link or contact TMDA programmers.")

                    if Form["a%d" % Count].value == "pass": continue
                    try:
                        MsgObj = Pending.Message(Form["m%d" % Count].value)
                        if Form["a%d" % Count].value == "release":
                            ReleaseList.append(MsgObj)
                        elif Form["a%d" % Count].value == "delete":
                            DeleteList.append(MsgObj)
                        elif Form["a%d" % Count].value == "whitelist":
                            WhiteList.append(MsgObj)
                            ReleaseList.append(MsgObj)
                        elif Form["a%d" % Count].value == "blacklist":
                            BlackList.append(MsgObj)
                            DeleteList.append(MsgObj)
                        elif Form["a%d" % Count].value == "report":
                            OtherAction = "Report"
                            OtherList.append(MsgObj)
                        elif Form["a%d" % Count].value == "other":
                            if Form["Action"].value == "Release":
                                ReleaseList.append(MsgObj)
                            elif Form["Action"].value == "Delete":
                                DeleteList.append(MsgObj)
                            elif Form["Action"].value == "Whitelist":
                                WhiteList.append(MsgObj)
                                ReleaseList.append(MsgObj)
                            elif Form["Action"].value == "Blacklist":
                                BlackList.append(MsgObj)
                                DeleteList.append(MsgObj)
                            elif Form["Action"].value == "Read":
                                ReadList.append(MsgObj)
                            else:
                                OtherList.append(MsgObj)
                                OtherAction = Form["Action"].value
                    except (IOError, Errors.MessageError):
                        pass
                # Check for checkboxes (c0 through c%(PagerSize)d)
                elif Form.has_key("c%d" % Count):
                    # Check to make sure they're not trying to access anything other than
                    # email
                    if not GoodFN.search(Form["m%d" % Count].value):
                        CgiUtil.TermError(
                            "<tt>%s</tt> is not a valid message ID." %
                            Form["m%d" % Count].value,
                            "Program error / corrupted link.",
                            "process pending e-mail", "",
                            "Recheck link or contact TMDA programmers.")

                    try:
                        MsgObj = Pending.Message(Form["m%d" % Count].value)
                        if Form.has_key("ReleaseButton"):
                            ReleaseList.append(MsgObj)
                        elif Form.has_key("DeleteButton"):
                            DeleteList.append(MsgObj)
                        elif Form.has_key("BlacklistButton"):
                            BlackList.append(MsgObj)
                            DeleteList.append(MsgObj)
                        elif Form.has_key("WhitelistButton"):
                            WhiteList.append(MsgObj)
                            ReleaseList.append(MsgObj)
                        elif Form.has_key("ReportButton"):
                            OtherAction = "Report"
                            OtherList.append(MsgObj)
                        elif Form.has_key("ExecuteButton"):
                            OtherAction = Form["Action"].value
                            if OtherAction == "Release":
                                ReleaseList.append(MsgObj)
                            elif OtherAction == "Delete":
                                DeleteList.append(MsgObj)
                            elif OtherAction == "Whitelist":
                                WhiteList.append(MsgObj)
                                ReleaseList.append(MsgObj)
                            elif OtherAction == "Blacklist":
                                BlackList.append(MsgObj)
                                DeleteList.append(MsgObj)
                            elif OtherAction == "Read":
                                ReadList.append(MsgObj)
                            else:
                                OtherList.append(MsgObj)
                    except IOError:
                        pass
            # Process the messages found:
            # Apply "other" action... May be Report or a custom filter
            for MsgObj in OtherList:
                if OtherAction == "Report":
                    CgiUtil.ReportToSpamCop(MsgObj)
                    DeleteList.append(MsgObj)
                # TODO: Check if OtherAction is a custom filter
                #       If so, run it on the message and check the return value
                #       and add the MsgObj to the appropriate action list based on the
                #       filter output.
            for MsgObj in WhiteList:
                # Whitelist (and release) each message
                MsgObj.whitelist()
            for MsgObj in ReleaseList:
                # Release each message
                PVars["InProcess"][MsgObj.msgid] = 1
                MsgObj.release()
            for MsgObj in BlackList:
                # Blacklist (and delete) each message
                MsgObj.blacklist()
            for MsgObj in DeleteList:
                # Delete each message
                MsgObj.delete()

    # Locate messages in pending dir
    Queue = Pending.Queue(descending=1, cache=1)
    try:
        Queue.initQueue()
        Queue._loadCache()
        Msgs = Queue.listPendingIds()
    except (Errors.QueueError, TypeError):
        Msgs = []

    # Search the Pending List:
    #
    #  If the from has the keys searchPattern and search
    #  we can search.
    #
    #  - searchPattern: a basic RE pattern which contains exactly one "%s"
    #    where the user's search string goes.
    #  - search: The user's search string for incorporation into the searchPattern
    #
    # For an example, check out the source for the Pending List in the theme
    # 'Blue'
    #
    Searching = 0
    if Form.has_key("searchPattern") and Form.has_key("search"):
        Searching = 1
        # By default, set no flags.
        flags = 0

        # Check what sort of search - a full body search or just a header search
        if (re.search('%s', Form['searchPattern'].value)):
            searchScope = 'fullMessage'
            expression = Form['searchPattern'].value % Form['search'].value
            # Do a multiline search through the entire message, matching a newline
            # with '.'
            flags = re.MULTILINE | re.DOTALL
        elif (re.match('^_header:', Form['searchPattern'].value)):
            (searchScope, headerList) = Form['searchPattern'].value.split(':')
            headerList = headerList.split(',')
            expression = Form['search'].value
        elif( Form['searchPattern'].value == "_header" and \
              Form.has_key("searchHeaderList" ) ):
            searchScope = Form['searchPattern'].value
            headerList = Form['searchHeaderList'].value.split(',')
            expression = Form['search'].value

        # Assume case-insensitive unless the form has 'searchCaseSensitive'
        if not Form.has_key("searchCaseSensitive"):
            flags = flags | re.I

        exp = re.compile(expression, flags)
        matchingMsgs = []
        for Msg in Msgs:
            try:
                MsgObj = Pending.Message(Msg)
            except (IOError, Errors.MessageError, TypeError), ErrStr:
                continue
            # Slow search - Search the fulltext of the message
            if searchScope == 'fullMessage' and \
               exp.search( MsgObj.show() ) != None:
                matchingMsgs = matchingMsgs + [Msg]
            # Faster search - just matches a header
            elif searchScope == '_header':
                for header in headerList:
                    if MsgObj.msgobj.has_key( header ) and \
                       exp.search( MsgObj.msgobj[ header ] ):
                        matchingMsgs = matchingMsgs + [Msg]
                        break
        Msgs = matchingMsgs
Beispiel #12
0
        RowBgColor = None
    if len(Msgs):
        # Add rows for messages if there are any
        Count = 0
        #InProcMsg = ""
        inProcessLine = 0
        for Msg in Msgs[FirstMsg:LastMsg]:
            T["MsgID"] = Msg
            if Count % 2 == 0 and OddRowColor is not None:
                T["RowBgColor"] = OddRowColor
            elif EvenRowColor is not None:
                T["RowBgColor"] = EvenRowColor

            # Print a single message record inside list loop
            try:
                MsgObj = Pending.Message(Msg)
            except (IOError, Errors.MessageError, \
                    email.Errors.MessageError), ErrStr:
                continue

            # Message size
            T["Size"] = CgiUtil.Size(MsgObj)

            # Find preferred date
            DateFormat = PVars[("PendingList", "DateFormat")]
            MsgTime = int(MsgObj.msgid.split('.')[0])
            if DateFormat == "DaysAgo":
                # Special Case!  "n days ago"
                Today = (int(time.time()) / 86400)
                MsgDay = (MsgTime / 86400)
                DaysAgo = Today - MsgDay