Add MMS sending capacilities #1

Merged
alex merged 12 commits from dev into master 2021-05-21 05:57:05 +00:00
3 changed files with 85 additions and 95 deletions
Showing only changes of commit 213d73a475 - Show all commits

5
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,5 @@
{
"python.linting.flake8Enabled": true,
"python.linting.pylintEnabled": false,
"python.linting.enabled": true
}

View file

@ -18,7 +18,6 @@ By default:
- python3
- python3-aiosmtpd
- python3-pydbus
- python-messaging (pip install python-messaging)
### setup
Install the dependency and mms2mail (on debian based distribution):
@ -26,7 +25,6 @@ Install the dependency and mms2mail (on debian based distribution):
sudo apt-get install python3
sudo apt-get install python3-pydbus
sudo apt-get install python3-aiosmtpd
pip install --user python-messaging
mkdir -p ~/.local/bin
cp mms2mail ~/.local/bin
@ -66,23 +64,24 @@ port = 2525
### reference
```
mms2mail [-h] [-d | -f FILES [FILES ...]] [--disable-smtp] [--disable-mms-delivery] [--delete] [--force-read] [--force-unlock] [-l {critical,error,warning,info,debug}]
mms2mail [-h] [--disable-smtp] [--disable-mms-delivery] [--force-read] [--force-unlock] [-l {critical,error,warning,info,debug}]
optional arguments:
-h, --help show this help message and exit
-d, --daemon start in daemon mode
-f FILES [FILES ...], --file FILES [FILES ...]
Start in batch mode, parse specified mms files
--disable-smtp
--disable-mms-delivery
--delete Ask mmsd to delete the converted MMS
--force-read Force conversion even if MMS is marked as read
--force-unlock BEWARE COULD LEAD TO WHOLE MBOX CORRUPTION Force unlocking the mbox after a few minutes /!\
-l {critical,error,warning,info,debug}, --logging {critical,error,warning,info,debug}
Define the logger output level
```
### Using with Mutt :
### Sending MMS
To send MMS, mail address not in the following format would be ignored :
```+123456789@domain``` with phone number in international format.
#### with Mutt :
To be able to send mms with mutt you need it to be built with SMTP support.
And and the following line in your ```$HOME/.muttrc```:
```

132
mms2mail
View file

@ -9,12 +9,12 @@ import time
import logging
from pathlib import Path
from messaging.mms.message import MMSMessage
import mailbox
import email
from gi.repository import GLib
import pydbus
from pydbus import SessionBus
from datetime import datetime
import os
import re
@ -87,13 +87,16 @@ class MMS2Mail:
"""
self.dbus = dbusmmsd
def check_mms(self, path):
def check_mms(self, path, properties):
"""
Check wether the provided file would be converted.
:param path: the mms filesystem path
:type path: str
:param properties: the mms properties
:type properties: Array
:return the mms status or None
:rtype str
"""
@ -121,7 +124,7 @@ class MMS2Mail:
else:
log.debug(f"New outgoing MMS found ({name.split('/')[-1]})")
def convert(self, path, dbus_path=None, properties=None):
def convert(self, path, dbus_path, properties):
"""
Convert a provided mms file to a mail stored in a mbox.
@ -130,80 +133,77 @@ class MMS2Mail:
:param dbus_path: the mms dbus path
:type dbus_path: str
:param properties: the mms properties
:type properties: Array
"""
# Check if the provided file present
status = self.check_mms(path)
status = self.check_mms(path, properties)
if not status:
log.error("MMS file not convertible.")
return
# Generate its dbus path, for future operation (mark as read, delete)
if not dbus_path:
dbus_path = f"/org/ofono/mms/modemmanager/{path.split('/')[-1]}"
mms = MMSMessage.from_file(path)
message = email.message.EmailMessage()
# Generate Mail Headers
mms_h_from = mms.headers.get('From', 'unknown/undef')
log.debug(f"MMS[From]: {mms_h_from}")
if 'not inserted' in mms_h_from:
mms_h_from = 'unknown/undef'
mms_from, mms_from_type = mms_h_from.split('/')
mms_from = properties.get('Sender', "unknown")
log.debug(f"MMS[From]: {mms_from}")
if '@' in mms_from:
message['From'] = mms_from
else:
message['From'] = f"{mms_from}@{self.domain}"
mms_h_to = mms.headers.get('To', 'unknown/undef')
log.debug(f"MMS[To]: {mms_h_to}")
if 'not inserted' in mms_h_to:
mms_h_to = 'unknown/undef'
mms_to, mms_to_type = mms_h_to.split('/')
message['To'] = f"{mms_to}@{self.domain}"
# Get other recipients from dbus signal
# https://github.com/pmarti/python-messaging/issues/49
if properties:
cc = ""
to = properties.get('Modem Number', None)
if to:
message['To'] = f"{mms_from}@{self.domain}"
recipients = ""
for r in properties['Recipients']:
if mms_to in r:
if to and to in r:
continue
log.debug(f'MMS/MAIL CC : {r}')
cc += f"{r}@{self.domain},"
if cc:
cc = cc[:-1]
message['CC'] = cc
if 'Subject' in mms.headers and mms.headers['Subject']:
message['Subject'] = mms.headers['Subject']
log.debug(f'MMS[CC] : {r}')
if '@' in r:
recipients += f"{r},"
else:
if status == 'sent' or status == 'draft':
message['Subject'] = f"MMS to {mms_to}"
recipients += f"{r}@{self.domain},"
if recipients:
recipients = recipients[:-1]
if to:
message['CC'] = recipients
else:
message['Subject'] = f"MMS from {mms_from}"
message['To'] = recipients
if 'Date' in mms.headers and mms.headers['Date']:
message['Date'] = mms.headers['Date']
# Recopy MMS HEADERS
for header in mms.headers:
message.add_header(f"X-MMS-{header}", f"{mms.headers[header]}")
message['Subject'] = properties.get('Subject',
f"MMS from {mms_from}")
mms_date = properties.get('Date')
if mms_date:
mms_datetime = datetime.strptime(mms_date, '%Y-%m-%dT%H:%M:%S%z')
mail_date = email.utils.format_datetime(mms_datetime)
message['Date'] = mail_date or email.utils.formatdate()
message.preamble = "This mail is converted from a MMS."
body = ""
data_id = 1
attachments = []
for data_part in mms.data_parts:
datacontent = data_part.headers['Content-Type']
if datacontent is not None:
maintype, subtype = datacontent[0].split('/', 1)
if 'text/plain' in datacontent[0]:
encoding = datacontent[1].get('Charset', 'utf-8')
body += data_part.data.decode(encoding,
for attachment in properties['Attachments']:
cid = attachment[0]
mimetype = attachment[1]
contentfile = attachment[2]
offset = attachment[3]
size = attachment[4]
with open(contentfile, 'rb') as f:
f.seek(offset, 0)
content = f.read(size)
if mimetype is not None:
if 'text/plain' in mimetype:
mimetype, charset = mimetype.split(';', 1)
encoding = charset.split('=')[1]
body += content.decode(encoding,
errors='replace') + '\n'
continue
extension = str(mimetypes.guess_extension(datacontent[0]))
filename = datacontent[1].get('Name', str(data_id))
attachments.append([data_part.data, maintype,
maintype, subtype = mimetype.split('/', 1)
extension = str(mimetypes.guess_extension(mimetype))
filename = cid
attachments.append([content, maintype,
subtype, filename + extension])
data_id = data_id + 1
if body:
message.set_content(body)
for a in attachments:
@ -212,7 +212,8 @@ class MMS2Mail:
subtype=a[2],
filename=a[3])
# Add MMS binary file, for debugging purpose or reparsing in the future
# Add MMS binary file, for debugging purpose
# or reparsing in the future
if self.attach_mms:
with open(path, 'rb') as fp:
message.add_attachment(fp.read(),
@ -385,7 +386,7 @@ class DbusMMSd():
:type mms2mail: mms2mail()
"""
self.mms2mail = mms2mail
self.bus = pydbus.SessionBus()
self.bus = SessionBus()
def set_mms2mail(self, mms2mail):
"""
@ -534,13 +535,6 @@ class DbusMMSd():
def main():
"""Run the different functions handling mms and mail."""
parser = argparse.ArgumentParser()
mode = parser.add_mutually_exclusive_group()
mode.add_argument("-d", "--daemon",
help="start in daemon mode ",
action='store_true', dest='daemon')
mode.add_argument("-f", "--file", nargs='+',
help="Start in batch mode, parse specified mms files",
dest='files')
parser.add_argument('--disable-smtp', action='store_true',
dest='disable_smtp')
parser.add_argument('--disable-mms-delivery', action='store_true',
@ -585,12 +579,7 @@ def main():
force_unlock=args.force_unlock)
m.set_dbus(d)
if args.files:
for mms_file in args.files:
m.convert(path=mms_file)
return
elif args.daemon:
log.info("Starting mms2mail in daemon mode")
log.info("Starting mms2mail")
if not args.disable_smtp:
log.info("Activating smtp to mmsd server")
controller.start()
@ -599,9 +588,6 @@ def main():
d.set_mms2mail(m)
d.add_signal_receiver()
m.convert_stored_mms()
else:
parser.print_help()
return
d.run()
controller.stop()