Skip to content

Commit

Permalink
Release v1.16.0
Browse files Browse the repository at this point in the history
* Feature: Offer to pair with 8-character code.
* Feature: Video notes are received.
* Feature: Have option to display message ID in conversation.
  • Loading branch information
hoehermann committed Aug 7, 2024
1 parent d405466 commit 7de7a6e
Show file tree
Hide file tree
Showing 24 changed files with 278 additions and 185 deletions.
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,3 @@ out

build
ignore

src/go/go.sum
src/go/go.mod
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 1.16.0

* Feature: Offer to pair with 8-character code.
* Feature: Video notes are received.
* Feature: Have option to display message ID in conversation.

# 1.15.0

* Update: Depends on whatsmeow v0.0.0-20240521160649-74c49f5a7d31 or later.
Expand All @@ -13,7 +19,7 @@
* Feature: Installation into user's home directory (Linux only).
* Change: Incoming images can be shown in-line, offered as a file-transfer or both ("both" is new).
* Change: KeepAliveTimeout is ignored (was terminate connection).
* Bugfix: Upon re-connect chats currently open in Pidgin can be re-joined implicitly.
* Bugfix: Upon re-connect, chats currently open in Pidgin can be re-joined implicitly.
* Bugfix: Incoming newlines are converted to br-tags as it is the custom in libpurple.
* Bugfix: libgcc is now linked statically when building for win32 with GCC later than 4.7.2.

Expand Down
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ This is a re-write of [purple-gowhatsapp](https://github.com/hoehermann/purple-g

Standard features:

* Connecting to existing account via QR-code.
* Connecting to existing account via QR code or 8-character code.
* Receiving messages, sending messages.
* Receiving files (images, videos, voice, document, stickers).
* Receiving files (image, video and note, audio and voice, document, sticker).
* Received images are displayed in the conversation window (optional).
* Sending images as image messages.
* Sending JPEG images as image messages.
* Sending opus audio files as voice messages.
* Sending mp4 video files as video messages.
* Sending other files as documents.
Expand Down Expand Up @@ -154,8 +154,8 @@ For sending opus in ogg audio files as voice messages, add a static win32 build
You must enter your phone's internationalized number followed by `@s.whatsapp.net`.
Example: `123456789` from Germany would use `49123456789@s.whatsapp.net`.

* Upon login, a QR code is shown in a Pidgin request window.
Using your phone's camera, scan the code within 20 seconds – just like you would do with WhatsApp Web.
* Upon login, a QR code and the 8-character code is shown in a Pidgin request window.
Using your phone's camera, scan the code within 20 seconds or enter the 8-character code on your main device – just like you would do with WhatsApp Web.
*Note:* On headless clients such as Spectrum, the QR code will be wrapped in a message by a fake contact called "Logon QR Code". You may need to temporarily configure your UI to accept messages from unsolicited users for linking purposes.
Wait until the connection has been fully set up. Unfortunately, there is no progress indicator while keys are exchanged and old messages are fetched. Usually, a couple of seconds is enough. Some power users with many groups and contacts reported the process can take more than a minute. If the plug-in is not yet ready, outgoing messages may be dropped silently (see issue #142).

Expand Down Expand Up @@ -234,6 +234,9 @@ For sending opus in ogg audio files as voice messages, add a static win32 build

Note: Neither of these indicate whether the message has been received by the *contact*.

* `display-message-id`
If set to true, the ID of a text message will be appended to the displayed text. For outgoing messages, this only has effect if `echo-sent-messages` is set to `on-success`.

* `autojoin-chats`
Automatically join all chats representing the WhatsApp groups after connecting and every time group information is provided. This is useful for protocol bridges.

Expand Down Expand Up @@ -335,7 +338,7 @@ This plug-in supports a couple of "IRC-style" commands. The user can write them
Request the current list of participants. Can only be used in group chat conversations.

* `?presenceavailable`, `?presenceunavailable`, `?presence`
Overrides the presence which is being sent to WhatsApp servers. The displayed connection state may no longer match the advertised connection state. This can be used to appear unavailable while still being able to receive messages for logging or notification purposes. Using this command may result in unexpected behaviour. Use `/presence` (without a suffix) to give back control to the plug-in's internals.
Overrides the presence which is being sent to WhatsApp servers. The displayed connection state may no longer match the advertised connection state. This can be used to appear unavailable while still being able to receive messages for logging or notification purposes. Using this command may result in unexpected behaviour. Use `?presence` (without a suffix) to give back control to the plug-in's internals.

* `?logout`
Performs a log-out. The QR-code will be requested upon connecting again.
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.15.0
1.16.0
1 change: 1 addition & 0 deletions src/c/blist.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ void gowhatsapp_ensure_buddy_in_blist(
gowhatsapp_assume_buddy_online(account, buddy);

// update name after checking against local alias and persisted name
// TODO: merge changes from purple-presage
const char *local_alias = purple_buddy_get_alias(buddy);
const char *server_alias = purple_blist_node_get_string(&buddy->node, "server_alias");
if (display_name != NULL && !purple_strequal(local_alias, display_name) && !purple_strequal(server_alias, display_name)) {
Expand Down
4 changes: 4 additions & 0 deletions src/c/bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@ struct gowhatsapp_message {
PurpleAccount *account; /// pointer identifying the account
char *remoteJid; /// conversation identifier (may be a single contact or a group)
char *senderJid; /// message author's identifier (useful in group chats)
char *messageId; /// message ID
char *text; /// the message payload (interpretation depends on type)
char *pairing_code; /// 6-character pairing code
char *pairing_qrdata; /// the pairing QR-code raw data
char *pairing_qrterminal; /// graphical QR for printing on a terminal
char *name; /// remote user's name (chosen by them) or filename (in case of attachment)
void *blob; /// binary payload (used for inlining images)
char **participants; /// list of participants (for group chats)
Expand Down
1 change: 1 addition & 0 deletions src/c/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ CHARCONSTANT(GOWHATSAPP_INLINE_STICKERS_OPTION, "inline-stickers");
CHARCONSTANT(GOWHATSAPP_GROUP_IS_FILE_ORIGIN_OPTION, "group-is-file-origin");
CHARCONSTANT(GOWHATSAPP_AUTO_JOIN_CHAT_OPTION, "autojoin-chats");
CHARCONSTANT(GOWHATSAPP_BRIDGE_COMPATIBILITY_OPTION, "bridge-compatibility");
CHARCONSTANT(GOWHATSAPP_DISPLAY_MESSAGE_ID_OPTION, "display-message-id");
CHARCONSTANT(GOWHATSAPP_ECHO_OPTION, "echo-sent-messages");
CHARCONSTANT(GOWHATSAPP_MESSAGE_CACHE_SIZE_OPTION, "message-cache-size");
CHARCONSTANT(GOWHATSAPP_IGNORE_STATUS_BROADCAST_OPTION, "ignore-status-broadcast");
Expand Down
20 changes: 12 additions & 8 deletions src/c/display_message.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
#include "gowhatsapp.h"
#include "constants.h"

void gowhatsapp_display_text_message(PurpleConnection *pc, gowhatsapp_message_t *gwamsg, PurpleMessageFlags flags) {
g_return_if_fail(pc != NULL);
void gowhatsapp_display_text_message(PurpleConnection *connection, gowhatsapp_message_t *gwamsg, PurpleMessageFlags flags) {
g_return_if_fail(connection != NULL);
// WhatsApp is a plain-text protocol, but Pidgin expects HTML
// NOTE: This turns newlines into br-tags which may mess up textual representation of QR-codes
gchar * text = purple_markup_escape_text(gwamsg->text, -1);
gowhatsapp_display_message_common(pc, gwamsg->senderJid, gwamsg->remoteJid, text, gwamsg->timestamp, gwamsg->isGroup, gwamsg->isOutgoing, gwamsg->name, flags);
PurpleAccount *account = purple_connection_get_account(connection);
if (purple_account_get_bool(account, GOWHATSAPP_DISPLAY_MESSAGE_ID_OPTION, FALSE)) {
// for https://github.com/Juliaria08
gchar * text_with_id = g_strdup_printf("%s <span lang=\"id\">%s</span>", text, gwamsg->messageId);
g_free(text);
text = text_with_id;
}
gowhatsapp_display_message_common(connection, gwamsg->senderJid, gwamsg->remoteJid, text, gwamsg->timestamp, gwamsg->isGroup, gwamsg->isOutgoing, gwamsg->name, flags);
g_free(text);
}

Expand Down Expand Up @@ -53,10 +59,8 @@ void gowhatsapp_display_message_common(
}

if (isGroup) {
PurpleConversation *conv = gowhatsapp_enter_group_chat(pc, remoteJid, NULL);
if (conv != NULL) {
purple_serv_got_chat_in(pc, g_str_hash(remoteJid), senderJid, flags, text, timestamp);
}
gowhatsapp_enter_group_chat(pc, remoteJid, NULL);
purple_serv_got_chat_in(pc, g_str_hash(remoteJid), senderJid, flags, text, timestamp);
} else {
if (flags & PURPLE_MESSAGE_SEND) {
// display message sent from own account (other device as well as local echo)
Expand Down
2 changes: 1 addition & 1 deletion src/c/groups.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ gowhatsapp_roomlist_get_list(PurpleConnection *pc) {
g_return_val_if_fail(wpd != NULL, NULL);
PurpleRoomlist *roomlist = wpd->roomlist;
if (roomlist != NULL) {
purple_debug_info(GOWHATSAPP_NAME, "Already getting roomlist.");
purple_debug_info(GOWHATSAPP_NAME, "Already getting roomlist.\n");
return roomlist;
}
roomlist = purple_roomlist_new(account); // MEMCHECK: caller takes ownership
Expand Down
2 changes: 1 addition & 1 deletion src/c/login.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ gowhatsapp_store_credentials(PurpleAccount *account, char *credentials)
// Pidgin stores the credentials in the account settings
// since commit ee89203, spectrum supports this out of the box
// in bitlbee, this has no effect
// TODO: ask spectrum maintainer if storing in password woukd okay, too
// TODO: ask spectrum maintainer if storing in password would okay, too
// or do not store credentials at all (just use the username for look-up)
purple_account_set_string(account, GOWHATSAPP_CREDENTIALS_KEY, credentials);

Expand Down
8 changes: 8 additions & 0 deletions src/c/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@ gowhatsapp_add_account_options(GList *account_options)
FALSE
);
account_options = g_list_append(account_options, option);

// for https://github.com/Juliaria08
option = purple_account_option_bool_new( // MEMCHECK: account_options takes ownership
"Display message ID",
GOWHATSAPP_DISPLAY_MESSAGE_ID_OPTION,
FALSE
);
account_options = g_list_append(account_options, option);

return account_options;
}
2 changes: 1 addition & 1 deletion src/c/process_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ gowhatsapp_process_message(gowhatsapp_message_t *gwamsg)
gowhatsapp_handle_group(pc, gwamsg);
break;
default:
purple_debug_info(GOWHATSAPP_NAME, "handling this message type is not implemented");
purple_debug_info(GOWHATSAPP_NAME, "Handling this message type is not implemented.\n");
g_free(gwamsg->blob);
}
}
48 changes: 30 additions & 18 deletions src/c/qrcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,35 @@ gowhatsapp_close_qrcode(PurpleAccount *account)
}

static void
gowhatsapp_display_qrcode(PurpleAccount *account, const char * challenge, void * image_data, size_t image_data_len)
gowhatsapp_display_qrcode(PurpleAccount *account, const char *pairing_code, const char *qr_data, void * image_data, size_t image_data_len)
{
g_return_if_fail(account != NULL);

PurpleRequestFields *fields = purple_request_fields_new();
PurpleRequestFieldGroup *group = purple_request_field_group_new(NULL);
purple_request_fields_add_group(fields, group);

PurpleRequestField *string_field = purple_request_field_string_new("qr_string", "QR Code Data", challenge, FALSE);
purple_request_field_group_add_field(group, string_field);
PurpleRequestField *image_field = purple_request_field_image_new("qr_image", "QR Code Image", image_data, image_data_len);
purple_request_field_group_add_field(group, image_field);
{
PurpleRequestField *string_code = purple_request_field_string_new("pairing_code", "Pairing Code", pairing_code, FALSE);
purple_request_field_group_add_field(group, string_code);
}
{
PurpleRequestField *string_field = purple_request_field_string_new("qr_data", "QR Code Data", qr_data, FALSE);
purple_request_field_group_add_field(group, string_field);
}
{
PurpleRequestField *image_field = purple_request_field_image_new("qr_image", "QR Code Image", image_data, image_data_len);
purple_request_field_group_add_field(group, image_field);
}

const char *username = purple_account_get_username(account);
char *secondary = g_strdup_printf("WhatsApp account %s (multi-device mode must be enabled)", username); // MEMCHECK: released here
char *secondary = g_strdup_printf("WhatsApp account %s", username); // MEMCHECK: released here

gowhatsapp_close_qrcode(account);
purple_request_fields(
account, /*handle*/
"Logon QR Code", /*title*/
"Please scan this QR code with your phone", /*primary*/
"Please enter pairing code or scan the QR code", /*primary*/
secondary, /*secondary*/
fields, /*fields*/
"OK", G_CALLBACK(null_cb), /*OK*/
Expand All @@ -59,33 +67,37 @@ gowhatsapp_handle_qrcode(PurpleConnection *pc, gowhatsapp_message_t *gwamsg)
if (!ui_ops || !ui_ops->request_fields || gwamsg->blobsize <= 0) {
// The UI hasn't implemented the func we want, just output as a message instead
PurpleMessageFlags flags = PURPLE_MESSAGE_RECV;
gchar *msg_out;
int img_id = 0;
if (gwamsg->blobsize > 0) {
img_id = purple_imgstore_add_with_id(gwamsg->blob, gwamsg->blobsize, NULL); // MEMCHECK: released including gwamsg->blob by purple_imgstore_unref_by_id (see below)
}
gchar *msg_img = NULL;
if (img_id > 0) {
gwamsg->blob = NULL; // MEMCHECK: not our memory to free any more
msg_out = g_strdup_printf( // MEMCHECK: msg_out released here (see below)
"%s<br /><img id=\"%u\" alt=\"%s\"/><br />%s",
"Please scan this QR code with your phone and WhatsApp multi-device mode enabled:", img_id, gwamsg->text, gwamsg->name
);
msg_img = g_strdup_printf("<img id=\"%u\"/>", img_id); // MEMCHECK: released here (see below)
flags |= PURPLE_MESSAGE_IMAGES;
} else {
msg_out = g_strdup_printf( // MEMCHECK: msg_out released here (see below)
"%s<br />%s<br />%s",
"Please scan this QR code with your phone and WhatsApp multi-device mode enabled:", gwamsg->text, gwamsg->name
);
// NOTE: This turns the newlines into br-tags. Front-ends should know what they are doing.
gchar * qrterminal_html = purple_markup_escape_text(gwamsg->pairing_qrterminal, -1); // MEMCHECK: released here (see below)
msg_img = g_strdup_printf("Your UI does not handle images. The next lines emulate the QR code with text characters. If viewed with a mono-spaced font, scanning may succeed. In case you see the raw HTML (with br-tags), you need to convert them into newlines first.<br/>%s", qrterminal_html); // MEMCHECK: released here (see below)
g_free(qrterminal_html);
}
gchar *msg_out = g_strdup_printf(
"Please enter pairing code %s or scan the QR code with your phone.<br/>%s<br/>In case the QR code above does not work, this is the challenge data. Use the QR code generator of your choice to turn it into an image:<br/>%s",
gwamsg->pairing_code,
msg_img,
gwamsg->pairing_qrdata
); // MEMCHECK: released here (see below)
g_free(msg_img);
const gchar *who = "Logon QR Code";
purple_serv_got_im(pc, who, msg_out, flags, time(NULL));
g_free(msg_out);
if (img_id > 0) {
purple_imgstore_unref_by_id(img_id);
}
g_free(msg_out);
} else {
PurpleAccount *account = purple_connection_get_account(pc);
gowhatsapp_display_qrcode(account, gwamsg->text, gwamsg->blob, gwamsg->blobsize);
gowhatsapp_display_qrcode(account, gwamsg->pairing_code, gwamsg->pairing_qrdata, gwamsg->blob, gwamsg->blobsize);
}
g_free(gwamsg->blob);
}
2 changes: 1 addition & 1 deletion src/c/send_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ gowhatsapp_chat_send_file(PurpleConnection *pc, int id, const char *filename)
if (conv != NULL) {
const gchar *who = purple_conversation_get_data(conv, "name");
if (who != NULL) {
gowhatsapp_send_file(pc, who, (gchar *)filename);
gowhatsapp_send_file(pc, who, (gchar *)filename); // TODO: there should be a group flag here somewhere
}
}
// TODO: display error if conv or who are NULL
Expand Down
4 changes: 3 additions & 1 deletion src/c/send_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ send_message(PurpleConnection *pc, const gchar *who, const gchar *message, gbool
char *msg = purple_markup_strip_html(message); // Note: This turns newlines into spaces and <br> tags into newlines
PurpleAccount *account = purple_connection_get_account(pc);
char *w = (char *)who; // cgo does not suport const
return gowhatsapp_go_send_message(account, w, msg, is_group);
int ret = gowhatsapp_go_send_message(account, w, msg, is_group);
g_free(msg);
return ret;
}

int
Expand Down
24 changes: 15 additions & 9 deletions src/go/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ func gowhatsapp_go_query_group_participants(account *PurpleAccount, groupid *C.c
if groupid != nil {
go_groupid := C.GoString(groupid)
jid, err := parseJID(go_groupid)
// TODO: check that jid actually is a group jid, see https://github.com/hoehermann/purple-gowhatsapp/issues/195
if err == nil {
return participants_to_ntcstrarray(handler.query_group_participants_retry(jid, 1, 10, 0))
} else {
Expand Down Expand Up @@ -258,16 +259,18 @@ func gowhatsapp_go_request_profile_picture(account *PurpleAccount, who *C.char,
}

/*
* This will display a QR code via PurpleRequest API.
* This will display a QR code via PurpleRequest API
* or in a conversation window (depending on UI features and user settings).
*/
func purple_display_qrcode(account *PurpleAccount, terminal string, challenge string, png []byte) {
func purple_display_qrcode(account *PurpleAccount, piring_code string, qr_data string, qr_terminal string, png []byte) {
cmessage := C.struct_gowhatsapp_message{
account: account,
msgtype: C.char(C.gowhatsapp_message_type_login),
text: C.CString(challenge),
name: C.CString(terminal),
blob: C.CBytes(png),
blobsize: C.size_t(len(png)),
account: account,
msgtype: C.char(C.gowhatsapp_message_type_login),
pairing_code: C.CString(piring_code),
pairing_qrdata: C.CString(qr_data),
pairing_qrterminal: C.CString(qr_terminal),
blob: C.CBytes(png),
blobsize: C.size_t(len(png)),
}
C.gowhatsapp_process_message_bridge(cmessage)
}
Expand Down Expand Up @@ -309,7 +312,7 @@ func purple_disconnected(account *PurpleAccount) {
* This will display a text message.
* Single participants and group chats.
*/
func purple_display_text_message(account *PurpleAccount, remoteJid string, isGroup bool, isOutgoing bool, senderJid string, pushName *string, timestamp time.Time, text string) {
func purple_display_text_message(account *PurpleAccount, remoteJid string, isGroup bool, isOutgoing bool, senderJid string, pushName *string, timestamp time.Time, text string, id *string) {
cmessage := C.struct_gowhatsapp_message{
account: account,
msgtype: C.char(C.gowhatsapp_message_type_text),
Expand All @@ -323,6 +326,9 @@ func purple_display_text_message(account *PurpleAccount, remoteJid string, isGro
if pushName != nil {
cmessage.name = C.CString(*pushName)
}
if id != nil {
cmessage.messageId = C.CString(*id)
}
C.gowhatsapp_process_message_bridge(cmessage)
}

Expand Down
Loading

0 comments on commit 7de7a6e

Please sign in to comment.