This file is indexed.

/usr/bin/pycmail is in pycmail 0.1.4.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
#! /usr/bin/python

# Written by Radovan Garabik <garabik@melkor.dnp.fmph.uniba.sk>.
# For new versions, look at http://kassiopeia.juls.savba..sk/~garabik/software/pycmail.html

import sys, os, os.path, pwd, string, StringIO, re, time, traceback
import pprint, getopt
import rfc822, socket


def dotlock(file, sleeptime=8, retries=-1, locktimeout=None, suspend=16):
    args = "-%i -r %i -s %i" % (sleeptime, retries, suspend)
    if locktimeout:
        args = args + " -l %i" % locktimeout
    os.system(lockfilebin+" "+args+" "+file+".lock")

def dotunlock(file):
    os.unlink(file+".lock")

def dotlocked(file):
    return os.path.isfile(file+".lock")



class MailDestiny:

    def __init__(self, destinyname=""):
        self.destinyname = destinyname

    def name(self):
        return "generic mail destiny"


class DevNull(MailDestiny):
    "send mail to /dev/null"

    def __init__(self):
        pass

    def getfd(self):
        self.fd = open("/dev/null", "a")
        return self.fd

    def closefd(self):
        self.fd.close()

    def name(self):
        return "/dev/null"


class Pipe(MailDestiny):
    "send mail to another program - headers included"

    def getfd(self):
        self.fd = os.popen(self.destinyname, "w")
        return self.fd

    def closefd(self):
        self.fd.close()

    def name(self):
        return "Pipe to "+self.destinyname


class Forward(MailDestiny):
    "forward mail to another address"

    def getfd(self):
        self.fd = os.popen(sendmailbin+" -i "+self.destinyname, "w")
        return self.fd

    def closefd(self):
        self.fd.close()

    def name(self):
        return "Forward to "+self.destinyname


class MailDir(MailDestiny):
    "deliver mail to a maildir directory"

    def filename(self):
        return `long(time.time())`[:-1]+"."+`os.getpid()`+"."+socket.gethostname()

    def getfd(self):
        self.fname = self.filename()
        timer = 0
        while os.path.isfile(self.destinyname+"/tmp"+self.fname):
            time.sleep(2)
            timer = timer + 1
            if timer > 43200: # 24h
                # this should not happen
                Bounce("Unable to deliver.")
                return None
        try:
            os.makedirs(self.destinyname+"/tmp", 0700)
            os.makedirs(self.destinyname+"/cur", 0700)
            os.makedirs(self.destinyname+"/new", 0700)
        except:
            pass
        os.umask(077)
        self.fd=open(self.destinyname+"/tmp/"+self.fname,"a")
        return self.fd

    def closefd(self):
        self.fd.close()
        os.link(self.destinyname+"/tmp/"+self.fname, self.destinyname+"/new/"+self.fname)
        os.unlink(self.destinyname+"/tmp/"+self.fname)

    def name(self):
        return "MailDir "+self.destinyname


class MailBox(MailDestiny):
    "deliver mail to BSD mail folder - needs lockfile (from procmail package) for locking to work!"

    def lock(self):
        if self.destinyname == defaultbox:
            os.system(lockfilebin+" -l 600 -ml")
        else:
            dotlock(self.destinyname, locktimeout=600)

    def unlock(self):
        if self.destinyname == defaultbox:
            os.system(lockfilebin+" -mu")
        else:
            dotunlock(self.destinyname)

    def locked(self):
        return dotlocked(self.destinyname)

    def filename(self):
        return self.destinyname

    def getfd(self):
        self.lock()
        self.fname = self.filename()
        os.umask(077)
        self.fd=open(self.fname,"a")
        return self.fd

    def closefd(self):
        self.fd.close()
        self.unlock()

    def name(self):
        return "MailBox "+self.destinyname




def Debug(text="Debugging...", level=2):
    "print text if debuglevel >= level"
    if DEBUGLEVEL >=level:
        print 'DEBUG:', text


def Append(*dest):
    "add to the mail destination"
    global DESTINATION
    for i in dest:
        DESTINATION.append(i)

def Set(*dest):
    "set the mail destination"
    global DESTINATION
    DESTINATION = []
    for i in dest:
        DESTINATION.append(i)

def Junk():
    Set(DevNull())

def SetDefault():
    Set(default)



def SendMail(recipient, From=None, sender=None, subject=None, text="pycmail test mail"):
    "send mail"
    # to do: specify eventual additional headers as parameters
    if DEBUGLEVEL >= 2:
        Debug("sending mail to %s, Subject: %s" % (recipient, subject), 2)
        return
    if From == None:
        From = USERNAME
    if sender == None:
        sender = USERNAME
    #sm = os.popen(sendmailbin+" -t", "w")
    sm = os.popen(sendmailbin+" -t -r "+sender, "w")
    sm.write("From: %s\n" % From)
    sm.write("To: %s\n" % recipient)
    if subject:
        sm.write("Subject: %s\n" % subject)
    sm.write("\n")
    sm.write(text)
    sm.close()


def Reply(recipient=None, From=None, sender=None, subject=None, text="pycmail test reply"):
    "reply to the current mail"
    # to do: specify eventual additional headers as parameters
    if subject == None:
        subject = "Re: "+SUBJECT
    if recipient == None:
        recipient = mailmsg.getaddr('Reply-To:')[1] or ADDR_FROM[1]
    if recipient <> None:
        SendMail(recipient, From=From, sender=sender, subject=subject, text=text)


def Bounce(text="Mail bounced."):
    "bounce mail. This only prints the text to stdout, which causes MTA to bounce the message"
    Debug("Bouncing mail.", 2)
    print text


class PycmailStopException(Exception):
    "Exception raised and catched to signal end of script execution"
    pass

def Stop():
    raise PycmailStopException


def Contains(s, sub, case=None, rex=0, flags=None):
    """return true if sub occurs in s
    if rex == 1, do it as regular expression, else just substring
    if searching substrings, default case=0, if regexps, case=1"""
    if rex:
        if case == None:
            case = 1
        if flags == None:
            flags = re.M
        else:
            flags = flags+re.M
        if case:
            f = flags
        else:
            f = flags+re.I
        return re.search(sub, s or "", f)
    else:    
        if case == None:
            case = 0
        if not s:
            return False
        if case:
            return sub in s
        return sub.lower() in s.lower()

def InHeader(hname, sub, case=None, rex=0, flags=None):
    "return true if sub is in header with name hname"
    return Contains(mailmsg.getheader(hname), sub, case, rex, flags)

def untuple(list):
    "change list of tuples into tuple of lists"
    return map(lambda x: x[0], list), map(lambda x: x[1], list)



# start of program is here

USERNAME = pwd.getpwuid(os.getuid())[0]
USERHOME = pwd.getpwuid(os.getuid())[5]

DEBUGLEVEL = 0
TESTING = 0

try:
    optlist, args = getopt.getopt(sys.argv[1:], "td:c:D:", 
                        ["debuglevel=", "config="])
except:
    optlist, args = [], []

if not args:
    args = [sys.stdin]

user_pycmailrc = USERHOME+"/.pycmailrc"
DEFINES=[]

for i in optlist:
    if i[0] in ['-d', '--debuglevel']:
        DEBUGLEVEL = string.atoi(i[1])
    if i[0] in ['-t', '--test']:
        TESTING = 1
    if i[0] in ['-c', '--config']:
        user_pycmailrc = os.path.expanduser(i[1])
    if i[0] == "-D":
    	DEFINES.append(i[1])


defaultbox = "/var/spool/mail/"+USERNAME
default = MailBox(defaultbox)
bufsize = 4096
bodysize = 1000

sendmailbin = "/usr/sbin/sendmail"
lockfilebin = "/usr/bin/lockfile"


SetDefault()  # we need to set it here and below too, just in case there
              # is an error in /etc/pycmailrc




if os.path.isfile("/etc/pycmailrc"):
    execfile("/etc/pycmailrc")
    
SetDefault()

for infile in args:
    try:
        if infile <> sys.stdin:
            infileds = open(infile)
        else:
            infileds = infile
        msg = ""

        while 1:
            l = infileds.readline()
            msg = msg+l
            if l == '\n' or l == "":
                message_read = 0
                if l == "":
                    # message contains only headers - a bit patological case,
                    # but we handle it anyway
                    BODY = ""
                    msg = msg + '\n'  # so that we do not corrupt next message
                    message_read = 1
                break
                    
        if not message_read:
            to_read = bufsize*(1+(len(msg)+bodysize)/bufsize)-len(msg)
            BODY = infileds.read(to_read)
            msg = msg + BODY
    
        msgIO = StringIO.StringIO(msg)
        mailmsg = rfc822.Message(msgIO)
        FROM = mailmsg.getheader('From') or ""
        TO = mailmsg.getheader('To') or ""
        CC = mailmsg.getheader('Cc') or ""
        SUBJECT = mailmsg.getheader('Subject') or ""
        ADDR_FROM = mailmsg.getaddr('From')
        ADDR_TO = mailmsg.getaddr('To')
        ADDR_CC = mailmsg.getaddr('Cc')
        NAMELIST_TO, ADDRLIST_TO = untuple(mailmsg.getaddrlist('To'))
        NAMELIST_CC, ADDRLIST_CC = untuple(mailmsg.getaddrlist('Cc'))
        msgIO.close()
    
        Debug("From: %s\nTo %s\nCC: %s\nSubject: %s" % (FROM, TO, CC, SUBJECT), 4)
        Debug("Message headers:\n"+pprint.pformat(mailmsg.headers), 6)
        Debug("Message body:\n"+BODY, 8)


        if os.path.isfile(user_pycmailrc):
            try:
                execfile(user_pycmailrc)
            except PycmailStopException:  # used to simulate a goto command
                pass 
            except:           # there is some error in .pycmailrc....
                SetDefault()  # delivery to system default mailbox
                if DEBUGLEVEL == 0:
                    pass
                elif DEBUGLEVEL >= 1:
                    traceback.print_exc()
    

        # I wonder if this is needed - user could have set DESTINATION to 
        # an empty list deliberately, as a faster variant to DevNull(),
        # but OTOH, he might have screwed it up.
        # for the time being, we assume he screwed it up and and fall back to 
        # default
        if DESTINATION == []:
            SetDefault()
    
        destfd = []
        for i in DESTINATION:
            Debug("destination: "+i.name(), 2)
            if not TESTING:
                fd = i.getfd()
                if fd:
                    Debug("writing headers+beginning of body", 4)
                    fd.write(msg)
                    destfd.append(fd)
    
    
        if not message_read:
            while 1:
                msg = infileds.read(bufsize)
                if msg == "":
                    break
                Debug("writing next chunk", 4)
                Debug("next chunk of body: \n%s\n" % msg, 10)
                if not TESTING:
                    for i in destfd:
                        i.write(msg)
    
    finally:
        infileds.close()
        for i in DESTINATION:
            try:
                if not TESTING:
                    i.closefd()
            except:
                if DEBUGLEVEL == 0:
                    pass
                elif DEBUGLEVEL >= 1:
                    traceback.print_exc()

Debug("end of run", 4)