root / pykota / trunk / bin / pkmail @ 2225

Revision 2216, 6.6 kB (checked in by jerome, 20 years ago)

Now exits with no traceback in case of Ctrl+C

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1#! /usr/bin/env python
2# -*- coding: ISO-8859-15 -*-
3
4# An email gateway for PyKota
5#
6# PyKota - Print Quotas for CUPS and LPRng
7#
8# (c) 2003, 2004, 2005 Jerome Alet <alet@librelogiciel.com>
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22#
23# $Id$
24#
25#
26
27import sys
28import os
29import popen2
30import smtplib
31import email
32
33from pykota.tool import PyKotaTool, PyKotaToolError, crashed, N_
34from pykota.pdlanalyzer import PDLAnalyzer, PDLAnalyzerError
35
36__doc__ = N_("""pkmail v%s (c) 2003, 2004, 2005 C@LL - Conseil Internet & Logiciels Libres
37
38Email gateway for PyKota.
39
40command line usage :
41
42  pkmail  [options]
43
44options :
45
46  -v | --version       Prints pkmail's version number then exits.
47  -h | --help          Prints this message then exits.
48 
49   
50  This command is meant to be used from your mail server's aliases file,
51  as a pipe. It will then accept commands send to it in email messages,
52  and will send the answer to the command's originator.
53 
54  To use this command, create an email alias in /etc/aliases with
55  the following format :
56 
57    pykotacmd: "|/usr/bin/pkmail"
58   
59  Then run the 'newaliases' command to regenerate the aliases database.
60 
61  You can now send commands by email to 'pykotacmd@yourdomain.com', with
62  the command in the subject.
63 
64  List of supported commands :
65 
66        report [username]
67 
68  NB : For pkmail to work correctly, you may have to put the 'mail'
69  system user in the 'pykota' system group to ensure this user can
70  read the /etc/pykota/pykotadmin.conf file, and restart your
71  mail server (e.g. /etc/init.d/exim restart). It is strongly advised
72  that you think at least twice before doing this though.
73 
74  Use at your own risk !
75 
76This program is free software; you can redistribute it and/or modify
77it under the terms of the GNU General Public License as published by
78the Free Software Foundation; either version 2 of the License, or
79(at your option) any later version.
80
81This program is distributed in the hope that it will be useful,
82but WITHOUT ANY WARRANTY; without even the implied warranty of
83MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
84GNU General Public License for more details.
85
86You should have received a copy of the GNU General Public License
87along with this program; if not, write to the Free Software
88Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
89
90Please e-mail bugs to: %s""")
91       
92       
93class PKMail(PyKotaTool) :       
94    """A class for pkmail."""
95    def main(self, files, options) :
96        """Accepts commands passed in an email message."""
97        data = sys.stdin.read()
98        message = email.message_from_string(data)
99        useremail = message["From"]
100        whoami = message["To"]
101        cmdargs = message["Subject"].split()
102        try :
103            (command, arguments) = (cmdargs[0].capitalize(), cmdargs[1:])
104        except IndexError :   
105            raise PyKotaToolError, "No command found !"
106       
107        badchars = """/<>&"'#!%*$,;\\"""
108        cheatmeonce = 0
109        for c in "".join(arguments) :
110            if c in badchars :
111                cheatmeonce = 1
112           
113        if cheatmeonce :   
114            self.logdebug("Possible intruder at %s : %s" % (useremail, str(arguments)))
115            result = "Either you mistyped your command, or you're a bad guy !"
116        else :
117            self.logdebug("Launching internal command '%s' with arguments %s" % (command, str(arguments)))
118            cmdfunc = getattr(self, "cmd%s" % command, self.cmdDefault)
119            result = cmdfunc(arguments)
120       
121        self.logdebug("Sending answer to : %s" % useremail)
122        server = smtplib.SMTP(self.smtpserver)
123        server.sendmail(whoami, [ useremail ], "From: %s\nTo: %s\nSubject: Result of your commands\n\n%s\n" % (whoami, useremail, result))
124        server.quit()
125        self.logdebug("Answer sent to : %s" % useremail)
126       
127        return 0
128       
129    def runCommand(self, cmd) :   
130        """Executes a command."""
131        self.logdebug("Launching : '%s'" % cmd)
132        os.environ["PATH"] = "%s:/bin:/usr/bin:/usr/local/bin:/opt/bin:/sbin:/usr/sbin" % os.environ.get("PATH", "")
133        child = popen2.Popen3(cmd)
134        child.tochild.close()
135        result = child.fromchild.read()
136        status = child.wait()
137        if os.WIFEXITED(status) :
138            status = os.WEXITSTATUS(status)
139        self.logdebug("'%s' exited with status %s" % (cmd, status))
140        return result
141       
142    def cmdDefault(self, arguments) :   
143        """Default command : sends an 'unknown command' message."""
144        return "Unknown command."
145       
146    def cmdReport(self, args) :   
147        """Generates a print quota report."""
148        return self.runCommand("repykota %s" % ' '.join([ '"%s"' % a for a in args ]))
149           
150if __name__ == "__main__" : 
151    retcode = 0
152    try :
153        defaults = { \
154                   }
155        short_options = "vh"
156        long_options = ["help", "version"]
157       
158        # Initializes the command line tool
159        mailparser = PKMail(doc=__doc__)
160        mailparser.deferredInit()
161       
162        # parse and checks the command line
163        (options, args) = mailparser.parseCommandline(sys.argv[1:], short_options, long_options, allownothing=1)
164       
165        # sets long options
166        options["help"] = options["h"] or options["help"]
167        options["version"] = options["v"] or options["version"]
168       
169        if options["help"] :
170            mailparser.display_usage_and_quit()
171        elif options["version"] :
172            mailparser.display_version_and_quit()
173        else :
174            retcode = mailparser.main(args, options)
175    except KeyboardInterrupt :       
176        sys.stderr.write("\nInterrupted with Ctrl+C !\n")
177    except SystemExit :       
178        pass
179    except :
180        try :
181            mailparser.crashed("pkmail failed")
182        except :   
183            crashed("pkmail failed")
184        retcode = -1
185
186    try :
187        mailparser.storage.close()
188    except (TypeError, NameError, AttributeError) :   
189        pass
190       
191    sys.exit(retcode)   
Note: See TracBrowser for help on using the browser.