annotate src/bnpparibas.py @ 0:02ec4a9ab0f0

Import
author Daniele Nicolodi <daniele.nicolodi@obspm.fr>
date Tue, 24 Feb 2015 15:50:21 +0100
parents
children ad577744dd8e
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
1 import email
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
2 import os.path
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
3 import re
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
4 import smtplib
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
5 import sqlite3
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
6 import subprocess
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
7 import textwrap
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
8
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
9 from collections import namedtuple, defaultdict
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
10 from contextlib import contextmanager
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
11 from datetime import datetime
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
12 from decimal import Decimal
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
13 from email.mime.text import MIMEText
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
14 from email.utils import format_datetime, localtime, parseaddr
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
15 from io import BytesIO
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
16 from itertools import product, islice
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
17 from urllib.parse import urljoin
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
18
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
19 import bs4
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
20 import numpy as np
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
21 import requests
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
22
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
23 from PIL import Image
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
24
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
25 DB = 'bnpparibas.sqlite'
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
26
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
27 # message template
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
28 MESSAGE = """\
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
29 From: {sender:}
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
30 Subject: {subject:}
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
31 Date: {date:}
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
32 Message-Id: {id:}
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
33
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
34 {body:}
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
35 """
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
36
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
37 # transaction template
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
38 HEADER = '{:14s} {:10s} {:59s} {:>8s}'.format('Id', 'Date', 'Description', 'Amount')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
39 TRANSACTION = '{id:} {date:%d/%m/%Y} {descr:59s} {amount:>8s}'
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
40
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
41 # as defined in bnpbaribas web app
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
42 CATEGORIES = {
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
43 '1': 'Alimentation',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
44 '7': 'Logement',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
45 '8': 'Loisirs',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
46 '9': 'Transport',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
47 '12': 'Opérations bancaires',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
48 '13': 'Non défini',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
49 '14': 'Multimédia',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
50 '20': 'Energies',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
51 '22': 'Retrait',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
52 '23': 'Sorties',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
53 'R58': 'Non défini',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
54 }
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
55
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
56 # euro symbol
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
57 EURO = b'\xe2\x82\xac'.decode('utf-8')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
58
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
59
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
60 # load configuration
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
61 from config import *
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
62
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
63
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
64 # GPG encrypted text is ascii and as such does not require encoding
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
65 # but its decrypted form is utf-8 and therefore the charset header
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
66 # must be set accordingly. define an appropriate charset object
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
67 email.charset.add_charset('utf8 7bit', header_enc=email.charset.SHORTEST,
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
68 body_enc=None, output_charset='utf-8')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
69
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
70
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
71 Message = namedtuple('Message', 'id read icon sender subject date validity'.split())
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
72
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
73
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
74 class Transaction:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
75 def __init__(self, tid, date, descr, debit, credit, category):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
76 self.id = tid
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
77 self.date = date
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
78 self.descr = descr
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
79 self.debit = debit
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
80 self.credit = credit
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
81 self.category = category
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
82
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
83 def __str__(self):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
84 # there does not seem to be an easy way to format Decimal
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
85 # objects with a leading sign in both the positive and
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
86 # negative value cases so do it manually
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
87 d = vars(self)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
88 if d['debit']:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
89 d['amount'] = '-' + str(d['debit'])
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
90 if d['credit']:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
91 d['amount'] = '+' + str(d['credit'])
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
92 return TRANSACTION.format(**d)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
93
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
94
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
95 def imslice(image):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
96 for x, y in product(range(0, 5), range(0, 5)):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
97 islice = image[27*x+1:27*(x+1), 27*y+1:27*(y+1), 0]
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
98 yield islice
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
99
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
100
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
101 def imdecode(image):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
102 keypad = np.load(os.path.join(os.path.dirname(__file__), 'keypad.npy'))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
103 immap = {}
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
104 for n, islice in enumerate(imslice(image)):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
105 # skip empty tiles
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
106 if np.mean(islice) > 248.0:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
107 continue
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
108 # compare to reference tiles
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
109 for d in range(0, 10):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
110 delta = np.sum(islice - keypad[d])
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
111 if delta < 100:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
112 print(delta)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
113 immap[d] = n + 1
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
114 return immap
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
115
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
116
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
117 def amountparse(value):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
118 # empty
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
119 if value == '\xa0':
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
120 return None
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
121 m = re.match(r'\s+((?:\d+\.)?\d+,\d+)\s+([^\s]+)\s+$', value, re.U|re.S)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
122 if m is None:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
123 raise ValueError(repr(value))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
124 # euro
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
125 currency = m.group(2)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
126 if currency != EURO:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
127 raise ValueError(repr(currency))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
128 return Decimal(m.group(1).replace('.', '').replace(',', '.'))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
129
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
130
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
131 class Site:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
132 def __init__(self):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
133 self.url = 'https://www.secure.bnpparibas.net'
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
134 self.req = requests.Session()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
135
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
136 def login(self, user, passwd):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
137 # login page
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
138 url = urljoin(self.url, '/banque/portail/particulier/HomeConnexion')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
139 r = self.req.get(url, params={'type': 'homeconnex'})
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
140 r.raise_for_status()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
141 # login form
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
142 soup = bs4.BeautifulSoup(r.text)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
143 form = soup.find('form', attrs={'name': 'logincanalnet'})
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
144 # extract relevant data
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
145 action = form['action']
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
146 data = { field['name']: field['value'] for field in form('input') }
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
147
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
148 # keyboard image url
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
149 src = ''
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
150 tag = soup.find(attrs={'id': 'secret-nbr-keyboard'})
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
151 for prop in tag['style'].split(';'):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
152 match = re.match(r'background-image:\s+url\(\'(.*)\'\)\s*', prop)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
153 if match:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
154 src = match.group(1)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
155 break
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
156 # download keyboard image
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
157 r = self.req.get(urljoin(self.url, src))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
158 image = np.array(Image.open(BytesIO(r.content)).convert('RGB'))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
159 # decode digits position
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
160 passwdmap = imdecode(image)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
161
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
162 # encode password
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
163 passwdenc = ''.join('%02d' % passwdmap[d] for d in map(int, passwd))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
164
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
165 # username and password
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
166 data['ch1'] = user
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
167 data['ch5'] = passwdenc
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
168
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
169 # post
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
170 r = self.req.post(urljoin(self.url, action), data=data)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
171 r.raise_for_status()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
172 # redirection
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
173 m = re.search(r'document\.location\.replace\(\"(.+)\"\)', r.text)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
174 dest = m.group(1)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
175 r = self.req.get(dest)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
176 r.raise_for_status()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
177
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
178 # check for errors
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
179 soup = bs4.BeautifulSoup(r.text)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
180 err = soup.find(attrs={'class': 'TitreErreur'})
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
181 if err:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
182 raise ValueError(err.text)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
183
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
184
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
185 def recent(self):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
186 data = {
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
187 'BeginDate': '',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
188 'Categs': '',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
189 'Contracts': '',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
190 'EndDate': '',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
191 'OpTypes': '',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
192 'cboFlowName': 'flow/iastatement',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
193 'contractId': CONTRACT,
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
194 'contractIds': '',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
195 'entryDashboard': '',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
196 'execution': 'e6s1',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
197 'externalIAId': 'IAStatements',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
198 'g1Style': 'expand',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
199 'g1Type': '',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
200 'g2Style': 'collapse',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
201 'g2Type': '',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
202 'g3Style': 'collapse',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
203 'g3Type': '',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
204 'g4Style': 'collapse',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
205 'g4Type': '',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
206 'groupId': '-2',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
207 'groupSelected': '-2',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
208 'gt': 'homepage:basic-theme',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
209 'pageId': 'releveoperations',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
210 'pastOrPendingOperations': '1',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
211 'sendEUD': 'true',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
212 'step': 'STAMENTS', }
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
213
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
214 url = urljoin(self.url, '/banque/portail/particulier/FicheA')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
215 r = self.req.post(url, data=data)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
216 r.raise_for_status()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
217 text = r.text
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
218
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
219 # the html is so broken beautifulsoup does not understand it
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
220 text = text.replace(
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
221 '<th class="thTitre" style="width:7%">Pointage </td>',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
222 '<th class="thTitre" style="width:7%">Pointage </th>')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
223 s = bs4.BeautifulSoup(text)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
224
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
225 # extract transactions
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
226 table = s.find('table', id='tableCompte')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
227 rows = table.find_all('tr')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
228 for row in rows:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
229 fields = row.find_all('td')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
230 if not fields:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
231 # skip headers row
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
232 continue
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
233 id = int(fields[0].input['id'].lstrip('_'))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
234 date = datetime.strptime(fields[1].text, '%d/%m/%Y')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
235 descr = fields[2].text.strip()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
236 debit = amountparse(fields[3].text)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
237 credit = amountparse(fields[4].text)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
238 category = fields[5].text.strip()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
239 categoryid = fields[6].span['class'][2][4:]
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
240 yield Transaction(id, date, descr, debit, credit, categoryid)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
241
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
242
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
243 def messages(self):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
244 data = {
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
245 'identifiant': 'BmmFicheListerMessagesRecus_20100607022434',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
246 'type': 'fiche', }
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
247
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
248 url = urljoin(self.url, '/banque/portail/particulier/Fiche')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
249 r = self.req.post(url, data=data)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
250 r.raise_for_status()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
251 s = bs4.BeautifulSoup(r.text)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
252
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
253 # messages list
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
254 table = s.find('table', id='listeMessages')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
255 for row in table.find_all('tr', recursive=False):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
256 # skip headers and separators
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
257 if 'entete' in row['class']:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
258 continue
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
259 # skip separators
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
260 if 'sep' in row['class']:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
261 continue
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
262 # skip footer
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
263 if 'actions_bas' in row['class']:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
264 continue
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
265 fields = row.find_all('td')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
266 icon = fields[1].img['src']
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
267 sender = fields[2].text.strip()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
268 subject = fields[4].a.text.strip()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
269 date = datetime.strptime(fields[5]['data'], '%Y/%m/%d:%Hh%Mmin%Ssec')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
270 validity = datetime.strptime(fields[6]['data'], '%Y/%m/%d:%Hh%Mmin%Ssec')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
271 m = re.match(r'''validerFormulaire\('BmmFicheLireMessage_20100607022346','(.+)','(true|false)'\);$''', fields[4].a['onclick'])
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
272 mid = m.group(1)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
273 read = m.group(2) == 'false'
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
274 yield Message(mid, read, icon, sender, subject, date, validity)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
275
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
276
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
277 def message(self, mid):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
278 data = {
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
279 'etape': 'boiteReception',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
280 'idMessage': mid,
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
281 'identifiant': 'BmmFicheLireMessage_20100607022346',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
282 'maxPagination': 2,
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
283 'minPagination': 1,
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
284 'nbElementParPage': 20,
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
285 'nbEltPagination': 5,
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
286 'nbPages': 2,
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
287 'newMsg': 'false',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
288 'pagination': 1,
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
289 'type': 'fiche',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
290 'typeAction': '', }
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
291
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
292 url = urljoin(self.url, '/banque/portail/particulier/Fiche')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
293 r = self.req.post(url, data=data)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
294 r.raise_for_status()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
295 # fix badly broken html
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
296 text = r.text.replace('<br>', '<br/>').replace('</br>', '')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
297 s = bs4.BeautifulSoup(text)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
298
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
299 envelope = s.find('div', attrs={'class': 'enveloppe'})
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
300 rows = envelope.find_all('tr')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
301 fields = rows[1].find_all('td')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
302 # the messages list present a truncated sender
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
303 sender = fields[0].text.strip()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
304 # not used
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
305 subject = fields[1].text.strip()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
306 date = fields[2].text.strip()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
307
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
308 content = s.find('div', attrs={'class': 'txtMessage'})
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
309 # clean up text
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
310 for t in content.find_all('style'):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
311 t.extract()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
312 for t in content.find_all('script'):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
313 t.extract()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
314 for t in content.find_all(id='info_pro'):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
315 t.extract()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
316 for t in content.find_all('br'):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
317 t.replace_with('\n\n')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
318 for t in content.find_all('b'):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
319 if t.string:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
320 t.replace_with('*%s*' % t.string.strip())
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
321 for t in content.find_all('li'):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
322 t.replace_with('- %s\n\n' % t.text.strip())
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
323 # format nicely
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
324 text = re.sub(' +', ' ', content.text)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
325 text = re.sub(r'\s+([\.:])', r'\1', text)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
326 pars = []
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
327 for p in re.split('\n\n+', text):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
328 p = p.strip()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
329 if p:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
330 pars.append('\n'.join(textwrap.wrap(p, 72)))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
331 body = '\n\n'.join(pars)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
332 return sender, body
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
333
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
334
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
335 def transactions(self):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
336 data = {'ch_memo': 'NON',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
337 'ch_rop_cpt_0': 'FR7630004001640000242975804',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
338 'ch_rop_dat': 'tous',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
339 'ch_rop_dat_deb': '',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
340 'ch_rop_dat_fin': '',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
341 'ch_rop_fmt_dat': 'JJMMAAAA',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
342 'ch_rop_fmt_fic': 'RTEXC',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
343 'ch_rop_fmt_sep': 'PT',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
344 'ch_rop_mon': 'EUR',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
345 'x': '55',
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
346 'y': '7'}
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
347 r = self.req.post(urljoin(self.url, '/SAF_TLC_CNF'), data=data)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
348 r.raise_for_status()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
349 s = bs4.BeautifulSoup(r.text)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
350 path = s.find('a')['href']
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
351 r = self.req.get(urljoin(self.url, path))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
352 r.raise_for_status()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
353 return r.text
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
354
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
355
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
356 class Mailer:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
357 def __init__(self):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
358 self.server = SMTPSERVER
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
359 self.port = SMTPPORT
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
360 self.starttls = SMTPSTARTTLS
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
361 self.username = SMTPUSER
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
362 self.password = SMTPPASSWD
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
363
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
364 @contextmanager
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
365 def connect(self):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
366 smtp = smtplib.SMTP(self.server, self.port)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
367 if self.starttls:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
368 smtp.starttls()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
369 if self.username:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
370 smtp.login(self.username, self.password)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
371 yield smtp
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
372 smtp.quit()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
373
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
374 def send(self, message, fromaddr=None, toaddr=None):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
375 if not fromaddr:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
376 fromaddr = message['From']
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
377 if not toaddr:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
378 toaddr = message['To']
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
379 with self.connect() as conn:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
380 conn.sendmail(fromaddr, toaddr, str(message))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
381
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
382
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
383 def encrypt(message, sender, recipient):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
384 sender = parseaddr(sender)[1]
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
385 recipient = parseaddr(recipient)[1]
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
386 cmd = [ "gpg", "--homedir", GNUPGHOME, "--batch", "--yes", "--no-options", "--armor",
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
387 "--local-user", sender, "--recipient", recipient, "--sign", "--encrypt"]
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
388 p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
389 encdata = p.communicate(input=message.encode('utf-8'))[0].decode('ascii')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
390 return encdata
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
391
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
392
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
393 def main():
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
394 bnp = Site()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
395 bnp.login(USERNAME, PASSWORD)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
396
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
397 db = sqlite3.connect(DB)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
398 db.execute('''CREATE TABLE IF NOT EXISTS messages (id TEXT PRIMARY KEY)''')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
399 db.execute('''CREATE TABLE IF NOT EXISTS transactions (id INTEGER PRIMARY KEY)''')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
400
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
401 mailer = Mailer()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
402
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
403 ## unread messages
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
404 messages = filter(lambda x: not x.read, bnp.messages())
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
405 for m in sorted(messages, key=lambda x: x.date):
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
406 curs = db.cursor()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
407 curs.execute('''SELECT IFNULL((SELECT id FROM messages WHERE id = ?), 0)''', (m.id, ))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
408 if curs.fetchone()[0]:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
409 # already handled
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
410 continue
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
411
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
412 # retrieve complete sender and message body
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
413 sender, body = bnp.message(m.id)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
414
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
415 # compose and send message
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
416 body = MESSAGE.format(id=m.id, sender=sender, date=m.date, subject=m.subject, body=body)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
417 message = MIMEText(encrypt(body, MAILFROM, MAILTO), _charset='utf8 7bit')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
418 message['Subject'] = 'BNP Paribas message'
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
419 message['From'] = MAILFROM
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
420 message['To'] = MAILTO
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
421 message['Date'] = format_datetime(localtime(m.date))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
422 mailer.send(message)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
423
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
424 curs.execute('''INSERT INTO messages (id) VALUES (?)''', (m.id, ))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
425 db.commit()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
426
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
427
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
428 ## transactions
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
429 transactions = bnp.recent()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
430 curs = db.cursor()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
431 lines = []
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
432 for t in transactions:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
433 curs.execute('''SELECT IFNULL((SELECT id FROM transactions WHERE id = ?), 0)''', (t.id, ))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
434 if curs.fetchone()[0]:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
435 # already handled
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
436 continue
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
437 lines.append(str(t))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
438 curs.execute('''INSERT INTO transactions (id) VALUES (?)''', (t.id, ))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
439
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
440 if lines:
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
441 lines.insert(0, HEADER)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
442 lines.insert(1, '-' * len(HEADER))
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
443 body = '\n'.join(lines)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
444 message = MIMEText(encrypt(body, MAILFROM, MAILTO), _charset='utf8 7bit')
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
445 message['Subject'] = 'BNP Paribas update'
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
446 message['From'] = MAILFROM
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
447 message['To'] = MAILTO
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
448 message['Date'] = format_datetime(localtime())
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
449 mailer.send(message)
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
450
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
451 db.commit()
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
452
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
453
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
454 if __name__ == '__main__':
Daniele Nicolodi <daniele.nicolodi@obspm.fr>
parents:
diff changeset
455 main()