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