-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathimport_pst.py
267 lines (231 loc) · 9.32 KB
/
import_pst.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#!/usr/bin/python
import os
import sys
import argparse
import subprocess
import re
import fnmatch
import datetime
import getpass
import requests
from icalendar import Calendar, Event, Timezone
VERSION = "1.0"
DEBUG = False
DRYRUN = False
EMAILS = True
CALENDARS = True
CONTACTS = True
OUR_TIMEZONE = 'Europe/London'
working_dir = os.path.dirname(os.path.abspath(__file__))
import_dir = os.path.join(working_dir, "pst")
converted_dir = os.path.join(working_dir, "converted")
def get_files(backup_dirs, include_files=[]):
import_files = []
include_files = r'|'.join([fnmatch.translate(x) for x in include_files]) or r'$.'
for backup_dir in backup_dirs:
for root, dirs, files in os.walk(backup_dir):
for fname in files:
# include files
if re.search(include_files, fname):
fname = os.path.join(root, fname)
if not os.path.islink(fname):
import_files.append(fname)
return import_files
def import_emails(user_dir, username):
folder_display = None
emails = get_files([user_dir], ['.eml'])
#print "Importing emails"
for email in emails:
folder = os.path.relpath(email, user_dir)
folder = folder.split('/')
folder.pop(0)
folder = os.path.normpath('/'.join(folder))
folder = os.path.split(folder)[0]
zarafadagent = ["zarafa-dagent", "-p", "/", "-C", "-F", folder, "-f", email, username]
if not DRYRUN:
try:
email_output = subprocess.check_output(zarafadagent)
except subprocess.CalledProcessError as e:
print email_output
print "Failed to import {}".format(email)
if folder_display != folder:
print "Imported {}".format(folder)
folder_display = folder
def import_calendars(user_dir, username, zadmin, zadmin_password):
IGNORE_DUPLICATE = True
url = "https://127.0.0.1:8443/ical/"+username
merged_ical = os.path.join(user_dir, 'merged.ics')
now = datetime.datetime.now()
icals = get_files([user_dir], ['.ics'])
# do nothing if no ics files found
if not icals:
return
# this set will be used fo find duplicate events
eventSet = set()
if DEBUG:
if IGNORE_DUPLICATE:
print 'ignore duplicated events'
# Open the new calendarfile and adding the information about this script to it
newcal = Calendar()
newcal.add('prodid', '-//py_zarafa_pst_importer//')
newcal.add('version', '2.0')
newcal.add('x-wr-calname', 'Default')
if DEBUG:
print 'new calendar ' + merged_ical + ' started'
# we need to add a timezone, because some clients want it (e.g. sunbird 0.5)
newtimezone = Timezone()
newtimezone.add('tzid', OUR_TIMEZONE)
newcal.add_component(newtimezone)
# Looping through the existing calendarfiles
for ical in icals:
try:
# open the file and read it
with open(ical,'rb') as calfile:
cal = Calendar.from_ical(calfile.read())
if DEBUG:
print 'reading file ' + ical
# every part of the file...
for component in cal.subcomponents:
# ...which name is VEVENT will be added to the new file
if component.name == 'VEVENT':
try:
if IGNORE_DUPLICATE:
eventId = str(component['dtstart']) + ' | ' + str(component['dtend']) + ' | ' + str(component['summary'])
if eventId not in eventSet:
eventSet.add(eventId)
else:
if DEBUG:
print 'skipped duplicated event: ' + eventId
continue
except:
# ignore events with missing dtstart, dtend or summary
if DEBUG:
print '! skipped an event with missing dtstart, dtend or summary. likely historic or duplicated event.'
continue
newcal.add_component(component)
except:
# if the file was not readable, we need a errormessage ;)
print 'Merge iCals: Error: reading file:', sys.exc_info()[1]
print ical
# After the loop, we have all of our data and can write the file now
try:
with open(merged_ical, 'wb') as f:
f.write(newcal.to_ical())
if DEBUG:
print 'new calendar written'
except:
print 'Merge iCals: Error: ', sys.exc_info()[1]
s = requests.Session()
s.auth = (zadmin, zadmin_password)
try:
#print "Importing Calendar"
with open(merged_ical, 'rb') as f:
r = s.put(url, verify=False, data=f)
if r.status_code == 200:
print "Successfully imported calendar"
else:
print "Failed to import calendar"
except:
print "Failed to connect with server"
def import_contacts():
print "No contacts will be imported. Need to code this"
def start_import_pst():
# Get Zarafa admin username and password
zadmin = raw_input('Enter Zarafa admin username: ')
zadmin_password = getpass.getpass()
try:
os.mkdir(converted_dir)
if DEBUG:
print "Created directory: ", converted_dir
except:
if DEBUG:
print "The directory already exists: ", converted_dir
files = [f for f in os.listdir(import_dir) if os.path.isfile(os.path.join(import_dir, f)) and f.endswith(".pst")]
for f in files:
try:
username = os.path.splitext(f)[0]
user_dir = os.path.join(converted_dir, username)
os.makedirs(user_dir)
if DEBUG:
print "Created directory: " + user_dir
readpst = ["readpst", "-e", "-o", user_dir, os.path.join(import_dir, f)]
try:
print "Converting PST for user: " + username
readpst_output = subprocess.check_output(readpst)
if DEBUG:
print "Converted: ", f
except subprocess.CalledProcessError as e:
print readpst_output
print "Failed to convert PST: ", f
#sys.exit(1)
except OSError:
if not os.path.isdir(user_dir):
print "Unable to create directory: ", user_dir
sys.exit(1)
else:
if DEBUG:
print "User directory for {} already exists: {}".format(username, user_dir)
if EMAILS:
print "Importing emails for user: " + username
import_emails(user_dir, username)
if CALENDARS:
print "Importing calendar for user: " + username
import_calendars(user_dir, username, zadmin, zadmin_password)
if CONTACTS:
print "Importing contacts for user: " + username
import_contacts()
def main():
'''Import PST files into Zarafa'''
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description = 'Import PST files into Zarafa',
epilog = """
This program will import emails, calendars and contacts from and Outlook PST file into a Zarafa server
You will need to create a directory called 'pst' in the same directory as this script.
In this directory place any PST file you want to import.
The name of the PST file must match the Zarafa username you want it imported into.
i.e.
Zarafa username: joeblog
PST name: joeblog.pst
"""
)
parser.add_argument('-V', '--version',
action='version',
version = '%(prog)s version: ' + VERSION)
parser.add_argument('--noemails', action = 'store_true', default = False,
help = "Don't import emails")
parser.add_argument('--nocalendars', action = 'store_true', default = False,
help = "Don't import calendars")
parser.add_argument('--nocontacts', action = 'store_true', default = False,
help = "Don't import contacts")
parser.add_argument('--debug', action = 'store_true', default = False,
help = "Print a bunch of debug info.")
parser.add_argument('--dryrun', action = 'store_true', default = False,
help = "Dry Run, do not actually import.")
args = parser.parse_args()
if args.debug:
global DEBUG
DEBUG = True
print 'Turning debug on'
if args.dryrun:
global DRYRUN
DRYRUN = True
print "Dry-run: sync or snapshot won't run"
if args.noemails:
global EMAILS
EMAILS = False
print "Not importing emails"
if args.nocalendars:
global CALENDARS
CALENDARS = False
print "Not importing calendars"
if args.nocontacts:
global CONTACTS
CONTACTS = False
print "Not importing contacts"
if EMAILS or CALENDARS or CONTACTS:
start_import_pst()
else:
print "You can't import nothing!!! Remove at least one of --noemails --nocalendars or --nocontacts"
if __name__ == '__main__':
main()