d5afd27d0c5c716403265d4b9255cfbd014356a3
[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
83 if mail.is_multipart():
84     telo = mail.get_payload(0).get_payload().strip()
85 else:
86     telo = mail.get_payload().strip()
87
88 if len(ocesat(telo, False)) < 2:
89     posli_mail(odesilatel, "Omluva", "Omlouvam se,"
90                    " ale Vase zprava je prilis kratka.\n")
91     sys.exit()
92 zprava = telo.upper()
93 analyza = []
94
95 # Puvodni zprava
96 analyza.append("Puvodni zprava:")
97 analyza.append(telo)
98
99 # Prepinani spacemodu
100 mod_m = False
101 mod_x = False
102 if 'X' in opsny:
103     mod_x = True
104 if 'M' in opsny:
105     mod_m = True
106 if 'A' in opsny:
107     mod_x = True
108     mod_m = True
109 if not mod_m and not mod_x:
110     if ' ' in ocesat(zprava, True)[1:-1]:
111         mod_m = True
112         analyza.append("\nAutomaticky zvolena analyza s mezerami.")
113     else:
114         mod_x = True
115         analyza.append("\nAutomaticky zvolena analyza bez mezer.")
116     
117 # Zakladni udaje
118 analyza.append("\nZakladni udaje:")
119 if mod_m:
120     analyza.append("Delka zpravy (vcetne mezer a zvlastnich znaku): " +
121                    str(len(zprava)))
122 analyza.append("Delka zpravy (bez mezer a zvlastnich znaku): " +
123                str(len(ocesat(zprava, False))))
124
125 # Prumerna delka slova
126 if mod_m:
127     analyza.append("\nPrumerna delka slova:")
128     slova = ocesat(zprava, True).split()
129     analyza.append('{0:.3}'.format(
130                    float(sum([len(word) for word in slova]))/len(slova)))
131
132 # Frekvence znaku 
133 analyza.append("\nFrekvencni analyza:")
134 freq = dict()
135 for char in ABECEDA:
136     freq[char] = 0
137 for char in zprava:
138     if char in freq:
139         freq[char] += 1
140 celkem = sum(freq.values())
141 for char in sorted(freq, key=freq.get, reverse=True):
142     analyza.append('{0} {1:>3} {2:>6.2%}'.format(char, freq[char],
143                    float(freq[char])/celkem))
144
145 # Index koincidence
146 if mod_m:
147     analyza.append("\nIndex koincidence (s mezerami):")
148     analyza.append('{0:.2%}'.format(
149                    koincidence.index_koincidence(zprava, True)))
150 if mod_x and len(zprava) >= 30:
151     #TODO tady by se spravne mela porovnavat delka ocesane zpravy
152     analyza.append("\nIndexy koincidence (bez mezer):")
153     analyza.append(koincidence.tabulka_indexu(zprava))
154
155 # Vigenere
156 if 'V' in opsny:
157     # TODO?poradne cteni opsnu
158     analyza.append("\nHeslo k Vigenerovi (" + opsny[-1] + "):")
159     vig_heslo, vig_text = vigenere.vsechno(zprava, int(opsny[-1]))
160     analyza.append(vig_heslo)
161     analyza.append(vig_text)
162
163 # Jakobsen
164 if mod_m:
165     analyza.append("\nJakobsen (s mezerami):")
166     analyza.append(jakobsen.desifruj(zprava))
167 if mod_x:
168     analyza.append("\nJakobsen (bez mezer):")
169     analyza.append(jakobsen.desifruj(zprava, False))
170
171 # Posuny v abecede
172 (posun, posunuty_text) = posuny.nejlepsi(zprava)
173 if 'P' in opsny or 'A' in opsny:
174     analyza.append("\nPosuny v abecede (nejlepsi posun {0}):".format(posun))
175     analyza.append("\n".join("{0:>2} {1}".format(
176                    i + 1, posuny.vsechny(zprava)[i]) for i in range(26)))
177 else:
178     analyza.append("\nNejlepsi posun ({0}):".format(posun))
179     analyza.append(posunuty_text)
180
181 # Bigramy
182 if 'B' in opsny or 'A' in opsny:
183     analyza.append("\nBigramy podle cetnosti:")
184     bigramy = dict()
185     for i in ABECEDA:
186         for j in ABECEDA:
187             bigramy[i+j] = 0
188     for i in range(0, len(zprava)-1):
189         if zprava[i:i+2] in bigramy:
190             bigramy[zprava[i:i+2]] += 1
191     celkem = sum(bigramy.values())
192     for char in sorted(bigramy, key=bigramy.get, reverse=True):
193         if bigramy[char] == 0:
194             break
195         analyza.append('{0} {1:>3} {2:>6.2%}'.format(char, bigramy[char],
196                        float(bigramy[char])/celkem))
197
198 # Podpis a pozdrav
199 analyza.append(''.join(["\nS pozdravem\nVas Robot\n"
200                         "\n--\nPro napovedu zaslete mail s predmetem \"",
201                         settings.subject," H\".\n"]))
202
203 # Odeslani odpovedi
204 posli_mail(odesilatel,
205            "Analyza Vasi zpravy",
206            "\n".join(analyza),
207            './robot_last.tmp')
208
209 f = open('./msg_last.tmp', 'w')
210 pickle.dump(mail, f)
211 f.close()
212
213 f = open('./robot.log', 'a')
214 m = re.match(r".*\<(.*)\>.*", odesilatel)
215 if m:
216     odesilatel2 = m.group(1)
217 else:
218     odesilatel2 = odesilatel
219 f.write(asctime() + " " +  odesilatel2 + " " + opsny + "\n")
220 f.close()