1package eu.siacs.conversations.services;
2
3import android.app.NotificationManager;
4import android.app.Service;
5import android.content.Context;
6import android.content.Intent;
7import android.os.IBinder;
8import android.support.v4.app.NotificationCompat;
9
10import java.io.BufferedWriter;
11import java.io.File;
12import java.io.FileWriter;
13import java.io.IOException;
14import java.text.SimpleDateFormat;
15import java.util.Date;
16import java.util.List;
17import java.util.concurrent.atomic.AtomicBoolean;
18
19import eu.siacs.conversations.R;
20import eu.siacs.conversations.entities.Account;
21import eu.siacs.conversations.entities.Conversation;
22import eu.siacs.conversations.entities.Message;
23import eu.siacs.conversations.persistance.DatabaseBackend;
24import eu.siacs.conversations.persistance.FileBackend;
25import rocks.xmpp.addr.Jid;
26
27public class ExportLogsService extends Service {
28
29 private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
30 private static final String DIRECTORY_STRING_FORMAT = FileBackend.getConversationsLogsDirectory() + "/logs/%s";
31 private static final String MESSAGE_STRING_FORMAT = "(%s) %s: %s\n";
32 private static final int NOTIFICATION_ID = 1;
33 private static AtomicBoolean running = new AtomicBoolean(false);
34 private DatabaseBackend mDatabaseBackend;
35 private List<Account> mAccounts;
36
37 @Override
38 public void onCreate() {
39 mDatabaseBackend = DatabaseBackend.getInstance(getBaseContext());
40 mAccounts = mDatabaseBackend.getAccounts();
41 }
42
43 @Override
44 public int onStartCommand(Intent intent, int flags, int startId) {
45 if (running.compareAndSet(false, true)) {
46 new Thread(() -> {
47 export();
48 stopForeground(true);
49 running.set(false);
50 stopSelf();
51 }).start();
52 }
53 return START_NOT_STICKY;
54 }
55
56 private void export() {
57 List<Conversation> conversations = mDatabaseBackend.getConversations(Conversation.STATUS_AVAILABLE);
58 conversations.addAll(mDatabaseBackend.getConversations(Conversation.STATUS_ARCHIVED));
59 NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
60 NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getBaseContext(), "export");
61 mBuilder.setContentTitle(getString(R.string.notification_export_logs_title))
62 .setSmallIcon(R.drawable.ic_import_export_white_24dp)
63 .setProgress(conversations.size(), 0, false);
64 startForeground(NOTIFICATION_ID, mBuilder.build());
65
66 int progress = 0;
67 for (Conversation conversation : conversations) {
68 writeToFile(conversation);
69 progress++;
70 mBuilder.setProgress(conversations.size(), progress, false);
71 if (mNotifyManager != null) {
72 mNotifyManager.notify(NOTIFICATION_ID, mBuilder.build());
73 }
74 }
75 }
76
77 private void writeToFile(Conversation conversation) {
78 Jid accountJid = resolveAccountUuid(conversation.getAccountUuid());
79 Jid contactJid = conversation.getJid();
80
81 File dir = new File(String.format(DIRECTORY_STRING_FORMAT, accountJid.asBareJid().toString()));
82 dir.mkdirs();
83
84 BufferedWriter bw = null;
85 try {
86 for (Message message : mDatabaseBackend.getMessagesIterable(conversation)) {
87 if (message == null)
88 continue;
89 if (message.getType() == Message.TYPE_TEXT || message.hasFileOnRemoteHost()) {
90 String date = simpleDateFormat.format(new Date(message.getTimeSent()));
91 if (bw == null) {
92 bw = new BufferedWriter(new FileWriter(
93 new File(dir, contactJid.asBareJid().toString() + ".txt")));
94 }
95 String jid = null;
96 switch (message.getStatus()) {
97 case Message.STATUS_RECEIVED:
98 jid = getMessageCounterpart(message);
99 break;
100 case Message.STATUS_SEND:
101 case Message.STATUS_SEND_RECEIVED:
102 case Message.STATUS_SEND_DISPLAYED:
103 jid = accountJid.asBareJid().toString();
104 break;
105 }
106 if (jid != null) {
107 String body = message.hasFileOnRemoteHost() ? message.getFileParams().url.toString() : message.getBody();
108 bw.write(String.format(MESSAGE_STRING_FORMAT, date, jid,
109 body.replace("\\\n", "\\ \n").replace("\n", "\\ \n")));
110 }
111 }
112 }
113 } catch (IOException e) {
114 e.printStackTrace();
115 } finally {
116 try {
117 if (bw != null) {
118 bw.close();
119 }
120 } catch (IOException e1) {
121 e1.printStackTrace();
122 }
123 }
124 }
125
126 private Jid resolveAccountUuid(String accountUuid) {
127 for (Account account : mAccounts) {
128 if (account.getUuid().equals(accountUuid)) {
129 return account.getJid();
130 }
131 }
132 return null;
133 }
134
135 private String getMessageCounterpart(Message message) {
136 String trueCounterpart = (String) message.getContentValues().get(Message.TRUE_COUNTERPART);
137 if (trueCounterpart != null) {
138 return trueCounterpart;
139 } else {
140 return message.getCounterpart().toString();
141 }
142 }
143
144 @Override
145 public IBinder onBind(Intent intent) {
146 return null;
147 }
148}