Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1559 support WhatsApp calls #1601

Merged
merged 11 commits into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ WhatsAppReport.ChatNowEncrypted=Messages to this chat and calls are now secured
WhatsAppReport.GroupNowEncrypted=Messages to this group are now secured with end-to-end encryption. Tap for more info.
WhatsAppReport.MissedVideoCall=Missed video call
WhatsAppReport.MissedVoiceCall=Missed voice call
WhatsAppReport.RefusedVoiceCall=Refused voice call
WhatsAppReport.RefusedVideoCall=Refused video call
WhatsAppReport.UnknownVoiceCall=Unknown type of voice call
WhatsAppReport.UnknownVideoCall=Unknown type of video call
WhatsAppReport.GroupCreated=Group created by
WhatsAppReport.UserJoinedGroup=User joined group:\
WhatsAppReport.UserLeftGroup=User left group:\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ WhatsAppReport.ChatNowEncrypted=Nachrichten an diesen Chat und Anrufe sind jetzt
WhatsAppReport.GroupNowEncrypted=Nachrichten an diese Gruppe sind jetzt mit Ende-zu-Ende-Verschlüsselung gesichert. Tippen Sie für weitere Informationen.
WhatsAppReport.MissedVideoCall=verpasste Videoanrufe
WhatsAppReport.MissedVoiceCall=verpasste Sprachanrufe
WhatsAppReport.RefusedVoiceCall=Refused voice call [TBT]
WhatsAppReport.RefusedVideoCall=Refused video call [TBT]
WhatsAppReport.UnknownVoiceCall=Unknown type of voice call [TBT]
WhatsAppReport.UnknownVideoCall=Unknown type of video call [TBT]
WhatsAppReport.GroupCreated=Gruppe erstellt von
WhatsAppReport.UserJoinedGroup=Benutzer ist Gruppe beigetreten:\
WhatsAppReport.UserLeftGroup=Benutzer hat Gruppe verlassen:\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ WhatsAppReport.ChatNowEncrypted=Los mensajes a este chat y las llamadas están a
WhatsAppReport.GroupNowEncrypted=Los mensajes a este grupo están ahora protegidos con encriptación de extremo a extremo. Pulse para obtener más información.
WhatsAppReport.MissedVideoCall=Videollamada perdida
WhatsAppReport.MissedVoiceCall=Llamada de voz perdida
WhatsAppReport.RefusedVoiceCall=Refused voice call [TBT]
WhatsAppReport.RefusedVideoCall=Refused video call [TBT]
WhatsAppReport.UnknownVoiceCall=Unknown type of voice call [TBT]
WhatsAppReport.UnknownVideoCall=Unknown type of video call [TBT]
WhatsAppReport.GroupCreated=Grupo creado por
WhatsAppReport.UserJoinedGroup=El usuario se unió al grupo:\
WhatsAppReport.UserLeftGroup=El usuario dejó el grupo:\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ WhatsAppReport.ChatNowEncrypted=I messaggi in questa chat e le chiamate sono ora
WhatsAppReport.GroupNowEncrypted=I messaggi a questo gruppo sono ora protetti con la crittografia end-to-end. Tocca per maggiori informazioni.
WhatsAppReport.MissedVideoCall=Videochiamata persa
WhatsAppReport.MissedVoiceCall=Chiamata vocale persa
WhatsAppReport.RefusedVoiceCall=Refused voice call [TBT]
WhatsAppReport.RefusedVideoCall=Refused video call [TBT]
WhatsAppReport.UnknownVoiceCall=Unknown type of voice call [TBT]
WhatsAppReport.UnknownVideoCall=Unknown type of video call [TBT]
WhatsAppReport.GroupCreated=Gruppo creato da
WhatsAppReport.UserJoinedGroup=Utente entrato nel gruppo:\
WhatsAppReport.UserLeftGroup=Utente ha lasciato il gruppo:\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ WhatsAppReport.ChatNowEncrypted=As mensagens e chamadas desta conversa estão pr
WhatsAppReport.GroupNowEncrypted=As mensagens deste grupo estão protegidas com a criptografia de ponta a ponta. Toque para mais informações.
WhatsAppReport.MissedVideoCall=Chamada de vídeo perdida
WhatsAppReport.MissedVoiceCall=Chamada de voz perdida
WhatsAppReport.RefusedVoiceCall=Chamada de voz perdida
WhatsAppReport.RefusedVideoCall=Chamada de vídeo perdida
WhatsAppReport.UnknownVoiceCall=Tipo de chamada de voz desconhecido
WhatsAppReport.UnknownVideoCall=Tipo de chamada de vídeo desconhecido
WhatsAppReport.GroupCreated=Grupo criado por
WhatsAppReport.UserJoinedGroup=Usuário adicionado no grupo:\
WhatsAppReport.UserLeftGroup=Usuário deixou o groupo:\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

import iped.parsers.sqlite.SQLite3DBParser;
import iped.parsers.whatsapp.Message.MessageStatus;
import iped.parsers.whatsapp.Message.MessageType;

/**
*
Expand Down Expand Up @@ -76,6 +77,8 @@ protected List<Chat> extractChatList() throws WAExtractorException {

for (Chat c : list) {
c.setMessages(extractMessages(conn, c));
c.getMessages().addAll(extractCalls(conn, c));
c.getMessages().sort((o1, o2) -> o1.getTimeStamp().compareTo(o2.getTimeStamp()));
if (c.isGroupChat()) {
setGroupMembers(c, conn, SELECT_GROUP_MEMBERS);
}
Expand Down Expand Up @@ -108,6 +111,52 @@ private void extractAddOns(Connection conn, Message m) throws SQLException {
}
}

private List<Message> extractCalls(Connection conn, Chat c) throws SQLException {
List<Message> messages = new ArrayList<>();

try (PreparedStatement stmt = conn.prepareStatement(SELECT_CALLS)) {
stmt.setFetchSize(1000);
stmt.setLong(1, c.getId());
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
Message m = new Message();
m.setRemoteId(c.getRemote().getFullId());
int call_result = rs.getInt("call_result");
if (account != null)
m.setLocalResource(account.getId());
m.setRemoteResource(rs.getString("remoteId"));
m.setId(rs.getLong("id"));
m.setCallId(rs.getString("call_id"));
if (rs.getInt("video_call") == 1) {
m.setMessageType(MessageType.UNKNOWN_VIDEO_CALL);
if (call_result == 5) {
m.setMessageType(VIDEO_CALL);
} else if (call_result == 4) {
m.setMessageType(MISSED_VIDEO_CALL);
} else if (call_result == 2) {
m.setMessageType(MessageType.REFUSED_VIDEO_CALL);
}
} else {
m.setMessageType(MessageType.UNKNOWN_VOICE_CALL);
if (call_result == 5) {
m.setMessageType(VOICE_CALL);
} else if (call_result == 4) {
m.setMessageType(MISSED_VOICE_CALL);
} else if (call_result == 2) {
m.setMessageType(MessageType.REFUSED_VOICE_CALL);
}
}
m.setFromMe(rs.getInt("from_me") == 1);
m.setMediaDuration(rs.getInt("duration"));
m.setTimeStamp(new Date(rs.getLong("timestamp")));

messages.add(m);
}

}

return messages;
}

private List<Message> extractMessages(Connection conn, Chat c) throws SQLException {
List<Message> messages = new ArrayList<>();
Expand Down Expand Up @@ -324,6 +373,11 @@ private static String getSelectMessagesQuery(Connection conn) throws SQLExceptio
+ " left join message_thumbnail mt on m._id=mt.message_row_id where chatId=? and status!=-1 ;";
}

private static final String SELECT_CALLS = "select c_l._id as id, c_l.call_id, c_l.video_call, c_l.duration, c_l.timestamp, c_l.call_result, c_l.from_me,\r\n"
+ " cv._id as chatId, cv.raw_string_jid as remoteId\r\n"
+ " from call_log c_l inner join chat c on c_l.jid_row_id=c.jid_row_id inner join chat_view cv on cv._id=c._id\r\n"
+ "where chatId=?";

private static final String SELECT_GROUP_MEMBERS = "select g._id as group_id, g.raw_string as group_name, u._id as user_id, u.raw_string as member "
+ "FROM group_participant_user gp inner join jid g on g._id=gp.group_jid_row_id inner join jid u on u._id=gp.user_jid_row_id where u.server='s.whatsapp.net' and u.type=0 and group_name=?"; //$NON-NLS-1$

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class Message {

private long id;
private int deletedId = -1;
private String callId = null;
private String remoteId;
private String remoteResource;
private String localResource;
Expand Down Expand Up @@ -98,15 +99,23 @@ public void setId(long id) {

/**
* Deleted recovered messages may have the same id as an allocated message. This
* returns a global unique id for a decoded database.
* returns a global unique id for a decoded database. Calls can also have the
* same id, so a new info is used as id
*
* @return a unique string id
*/
public String getUniqueId() {
String new_id = Long.toString(id);
if (callId != null) {
new_id += "_" + callId;
}
if (deletedId == -1) {
deletedId = deletedCounter.getAndIncrement();
}
return !deleted ? Long.toString(id) : id + "_" + deletedId;
if (deleted) {
new_id += "_" + deletedId;
}
return new_id;
}

public String getRemoteId() {
Expand Down Expand Up @@ -372,7 +381,9 @@ public boolean isSystemMessage() {

public boolean isCall() {
return messageType == MessageType.VIDEO_CALL || messageType == MessageType.VOICE_CALL
|| messageType == MessageType.MISSED_VIDEO_CALL || messageType == MessageType.MISSED_VOICE_CALL;
|| messageType == MessageType.MISSED_VIDEO_CALL || messageType == MessageType.MISSED_VOICE_CALL
|| messageType == MessageType.REFUSED_VIDEO_CALL || messageType == MessageType.REFUSED_VOICE_CALL
|| messageType == MessageType.UNKNOWN_VOICE_CALL || messageType == MessageType.UNKNOWN_VIDEO_CALL;
}

public String getRecoveredFrom() {
Expand Down Expand Up @@ -415,8 +426,16 @@ public List<MessageAddOn> getAddOns() {
return addOns;
}

public String getCallId() {
return callId;
}

public void setCallId(String callId) {
this.callId = callId;
}

public static enum MessageType {
TEXT_MESSAGE, IMAGE_MESSAGE, AUDIO_MESSAGE, VIDEO_MESSAGE, UNKNOWN_MEDIA_MESSAGE, CONTACT_MESSAGE, LOCATION_MESSAGE, SHARE_LOCATION_MESSAGE, VOICE_CALL, VIDEO_CALL, APP_MESSAGE, GIF_MESSAGE, MESSAGES_NOW_ENCRYPTED, ENCRIPTION_KEY_CHANGED, MISSED_VOICE_CALL, MISSED_VIDEO_CALL, DELETED_MESSAGE, DELETED_FROM_SENDER, GROUP_CREATED, USER_JOINED_GROUP, USER_JOINED_GROUP_FROM_LINK, USERS_JOINED_GROUP, USER_LEFT_GROUP, USER_REMOVED_FROM_GROUP, URL_MESSAGE, GROUP_ICON_CHANGED, GROUP_ICON_DELETED, GROUP_DESCRIPTION_CHANGED, SUBJECT_CHANGED, YOU_ADMIN, WAITING_MESSAGE, STICKER_MESSAGE, UNKNOWN_MESSAGE
TEXT_MESSAGE, IMAGE_MESSAGE, AUDIO_MESSAGE, VIDEO_MESSAGE, UNKNOWN_MEDIA_MESSAGE, CONTACT_MESSAGE, LOCATION_MESSAGE, SHARE_LOCATION_MESSAGE, VOICE_CALL, VIDEO_CALL, APP_MESSAGE, GIF_MESSAGE, MESSAGES_NOW_ENCRYPTED, ENCRIPTION_KEY_CHANGED, MISSED_VOICE_CALL, MISSED_VIDEO_CALL, DELETED_MESSAGE, DELETED_FROM_SENDER, GROUP_CREATED, USER_JOINED_GROUP, USER_JOINED_GROUP_FROM_LINK, USERS_JOINED_GROUP, USER_LEFT_GROUP, USER_REMOVED_FROM_GROUP, URL_MESSAGE, GROUP_ICON_CHANGED, GROUP_ICON_DELETED, GROUP_DESCRIPTION_CHANGED, SUBJECT_CHANGED, YOU_ADMIN, WAITING_MESSAGE, STICKER_MESSAGE, REFUSED_VIDEO_CALL, REFUSED_VOICE_CALL, UNKNOWN_VOICE_CALL, UNKNOWN_VIDEO_CALL, UNKNOWN_MESSAGE
}

public static enum MessageStatus {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,38 @@ private synchronized void printMessage(PrintWriter out, Message message, boolean
}
out.println(Messages.getString("WhatsAppReport.MissedVoiceCall")); //$NON-NLS-1$
break;
case REFUSED_VOICE_CALL:
if (message.isFromMe()) {
out.println("<div class=\"specialmessage to\">"); //$NON-NLS-1$
} else {
out.println("<div class=\"specialmessage from\">"); //$NON-NLS-1$
}
out.println(Messages.getString("WhatsAppReport.RefusedVoiceCall")); //$NON-NLS-1$
break;
case REFUSED_VIDEO_CALL:
if (message.isFromMe()) {
out.println("<div class=\"specialmessage to\">"); //$NON-NLS-1$
} else {
out.println("<div class=\"specialmessage from\">"); //$NON-NLS-1$
}
out.println(Messages.getString("WhatsAppReport.RefusedVideoCall")); //$NON-NLS-1$
break;
case UNKNOWN_VOICE_CALL:
if (message.isFromMe()) {
out.println("<div class=\"specialmessage to\">"); //$NON-NLS-1$
} else {
out.println("<div class=\"specialmessage from\">"); //$NON-NLS-1$
}
out.println(Messages.getString("WhatsAppReport.UnknownVoiceCall")); //$NON-NLS-1$
break;
case UNKNOWN_VIDEO_CALL:
if (message.isFromMe()) {
out.println("<div class=\"specialmessage to\">"); //$NON-NLS-1$
} else {
out.println("<div class=\"specialmessage from\">"); //$NON-NLS-1$
}
out.println(Messages.getString("WhatsAppReport.UnknownVideoCall")); //$NON-NLS-1$
break;
case VIDEO_CALL:
if (message.isFromMe()) {
out.println("<div class=\"specialmessage to\">"); //$NON-NLS-1$
Expand Down