podpora multipart message
[krypto.git] / robot.py
1 #!/usr/bin/env python
2
3 """Mailove rozhrani pro sadu kryptoanalytickych nastroju."""
4
5 import sys
6 import smtplib
7 import email
8 from email.mime.text import MIMEText
9 from time import asctime
10 from ocesavac import ocesat
11 import jakobsen
12 from jakobsen import reference
13 import koincidence
14 import posuny
15 import pickle
16 import os
17 import re
18 from spolecne import ABECEDA
19 import vigenere
20
21 class settings:
22     pass
23
24 settings = pickle.load(open('./robot_settings'))
25 os.chdir(settings.path)
26
27 def posli_mail(komu, predmet, text, loguj=None):
28     msg = MIMEText(text)
29     msg['Subject'] = predmet
30     msg['From'] = settings.name + " <" + settings.mail  + ">"
31     msg['To'] = komu
32     smtplib.SMTP('localhost').sendmail(settings.mail, komu, msg.as_string())
33     if loguj:
34         soubor = open(loguj, 'w')
35         soubor.write(msg.as_string())
36         soubor.close()
37
38 # Cteni mailu
39 mail = email.message_from_file(sys.stdin)
40 predmet, _, opsny = mail['Subject'].strip().upper().partition(' ')
41 odesilatel = mail['From']
42 if predmet != settings.subject:
43     sys.exit()
44 if opsny == 'H':
45     posli_mail(odesilatel, "Napoveda", ''.join("Napoveda:\n"
46                "Prikazy robotovi vkladejte do predmetu zpravy "
47                "zaslane na adresu ", 
48                settings.mail, ".\nNa velikosti pismen nezalezi."
49                "\n\nSeznam prikazu:\n"
50                "\"", settings.subject, "\"   Analyza zpravy z tela mailu.\n" 
51                "\"", settings.subject, " L\" Opakovana analyza "
52                "posledni zpravy.\n",
53                "\"", settings.subject, " X\" Vynuti analyzu bez mezer.\n"
54                "\"", settings.subject, " M\" Vynuti analyzu s mezerami.\n"
55                "\"", settings.subject, " B\" Vypise cetnost vsech bigramu.\n"
56                "\"", settings.subject, " P\" Vypise vsechny posunuti textu.\n"
57                "\"", settings.subject, " A\" Vypise uplne vsechno co dava "
58                "alespon trochu smysl (nedoporucuji).\n"
59                "\"", settings.subject, " H\" Tato napoveda.\n"
60                "\nVolby (mimo \"H\") je mozno libovolne kombinovat.\n"
61                "Napriklad \"", settings.subject, " LXB\" analyzuje posledni "
62                "prijatou zpravu s vynucenim analyzy bez mezer a navic vypise "
63                "cetnosti bigramu.\n"
64                "\nS pozdravem\nVas Robot\n"))
65     sys.exit()
66 if 'L' in opsny:
67     mail = pickle.load(open('./msg_last.tmp'))
68     m1 = re.match(r".*\<(.*)\>.*", mail['From'])
69     m2 = re.match(r".*\<(.*)\>.*", odesilatel)
70     if m1:
71         f1 = m1.group(1)
72     else:
73         f1 = mail['From']
74     if m2:
75         f2 = m2.group(1)
76     else:
77         f2 = odesilatel
78     if (f1 != f2):
79         posli_mail(odesilatel, "Omluva", "Omlouvam se,"
80                    " ale Vase zprava uz bohuzel neni na serveru ulozena.\n")
81         sys.exit()
82 if mail.is_multipart():
83     telo = mail.get_payload()[0].strip()
84 else:
85     telo = mail.get_payload().strip()
86
87 if len(ocesat(telo, False)) < 2:
88     posli_mail(odesilatel, "Omluva", "Omlouvam se,"
89                    " ale Vase zprava je prilis kratka.\n")
90     sys.exit()
91 zprava = telo.upper()
92 analyza = []
93
94 # Puvodni zprava
95 analyza.append("Puvodni zprava:")
96 analyza.append(telo)
97
98 # Prepinani spacemodu
99 mod_m = False
100 mod_x = False
101 if 'X' in opsny:
102     mod_x = True
103 if 'M' in opsny:
104     mod_m = True
105 if 'A' in opsny:
106     mod_x = True
107     mod_m = True
108 if not mod_m and not mod_x:
109     if ' ' in ocesat(zprava, True)[1:-1]:
110         mod_m = True
111         analyza.append("\nAutomaticky zvolena analyza s mezerami.")
112     else:
113         mod_x = True
114         analyza.append("\nAutomaticky zvolena analyza bez mezer.")
115     
116 # Zakladni udaje
117 analyza.append("\nZakladni udaje:")
118 if mod_m:
119     analyza.append("Delka zpravy (vcetne mezer a zvlastnich znaku): " +
120                    str(len(zprava)))
121 analyza.append("Delka zpravy (bez mezer a zvlastnich znaku): " +
122                str(len(ocesat(zprava, False))))
123
124 # Prumerna delka slova
125 if mod_m:
126     analyza.append("\nPrumerna delka slova:")
127     slova = ocesat(zprava, True).split()
128     analyza.append('{0:.3}'.format(
129                    float(sum([len(word) for word in slova]))/len(slova)))
130
131 # Frekvence znaku 
132 analyza.append("\nFrekvencni analyza:")
133 freq = dict()
134 for char in ABECEDA:
135     freq[char] = 0
136 for char in zprava:
137     if char in freq:
138         freq[char] += 1
139 celkem = sum(freq.values())
140 for char in sorted(freq, key=freq.get, reverse=True):
141     analyza.append('{0} {1:>3} {2:>6.2%}'.format(char, freq[char],
142                    float(freq[char])/celkem))
143
144 # Index koincidence
145 if mod_m:
146     analyza.append("\nIndex koincidence (s mezerami):")
147     analyza.append('{0:.2%}'.format(
148                    koincidence.index_koincidence(zprava, True)))
149 if mod_x and len(zprava) >= 10:
150     #TODO tady by se spravne mela porovnavat delka ocesane zpravy
151     analyza.append("\nIndexy koincidence (bez mezer):")
152     analyza.append(koincidence.tabulka_indexu(zprava))
153
154 # Vigenere
155 if 'V' in opsny:
156     analyza.append("\nHeslo k Vigenerovi (" + opsny[-1] + "):")
157     vig_heslo, vig_text = vigenere.vsechno(zprava, int(opsny[-1]))
158     analyza.append(vig_heslo)
159     analyza.append(vig_text)
160
161 # Jakobsen
162 if mod_m:
163     analyza.append("\nJakobsen (s mezerami):")
164     analyza.append(jakobsen.desifruj(zprava))
165 if mod_x:
166     analyza.append("\nJakobsen (bez mezer):")
167     analyza.append(jakobsen.desifruj(zprava, False))
168
169 # Posuny v abecede
170 (posun, posunuty_text) = posuny.nejlepsi(zprava)
171 if 'P' in opsny or 'A' in opsny:
172     analyza.append("\nPosuny v abecede (nejlepsi posun {0}):".format(posun))
173     analyza.append("\n".join("{0:>2} {1}".format(
174                    i + 1, posuny.vsechny(zprava)[i]) for i in range(26)))
175 else:
176     analyza.append("\nNejlepsi posun ({0}):".format(posun))
177     analyza.append(posunuty_text)
178
179 # Bigramy
180 if 'B' in opsny or 'A' in opsny:
181     analyza.append("\nBigramy podle cetnosti:")
182     bigramy = dict()
183     for i in ABECEDA:
184         for j in ABECEDA:
185             bigramy[i+j] = 0
186     for i in range(0, len(zprava)-1):
187         if zprava[i:i+2] in bigramy:
188             bigramy[zprava[i:i+2]] += 1
189     celkem = sum(bigramy.values())
190     for char in sorted(bigramy, key=bigramy.get, reverse=True):
191         if bigramy[char] == 0:
192             break
193         analyza.append('{0} {1:>3} {2:>6.2%}'.format(char, bigramy[char],
194                        float(bigramy[char])/celkem))
195
196 # Podpis a pozdrav
197 analyza.append(''.join(["\nS pozdravem\nVas Robot\n"
198                         "\n--\nPro napovedu zaslete mail s predmetem \"",
199                         settings.subject," H\".\n"]))
200
201 # Odeslani odpovedi
202 posli_mail(odesilatel,
203            "Analyza Vasi zpravy",
204            "\n".join(analyza),
205            './robot_last.tmp')
206
207 f = open('./msg_last.tmp', 'w')
208 pickle.dump(mail, f)
209 f.close()
210
211 f = open('./robot.log', 'a')
212 m = re.match(r".*\<(.*)\>.*", odesilatel)
213 if m:
214     odesilatel2 = m.group(1)
215 else:
216     odesilatel2 = odesilatel
217 f.write(asctime() + " " +  odesilatel2 + " " + opsny + "\n")
218 f.close()