Skip to content

Commit

Permalink
Offer to pair with character code.
Browse files Browse the repository at this point in the history
Added fields to message struct for more clarity.
  • Loading branch information
hoehermann committed Jul 25, 2024
1 parent 0d83860 commit cec0118
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 34 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ 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 (image, video and note, audio and voice, document, sticker).
* Received images are displayed in the conversation window (optional).
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 `[email protected]`.

* 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
3 changes: 3 additions & 0 deletions src/c/bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ struct gowhatsapp_message {
char *remoteJid; /// conversation identifier (may be a single contact or a group)
char *senderJid; /// message author's identifier (useful in group chats)
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: 0 additions & 1 deletion src/c/display_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
void gowhatsapp_display_text_message(PurpleConnection *pc, gowhatsapp_message_t *gwamsg, PurpleMessageFlags flags) {
g_return_if_fail(pc != 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);
g_free(text);
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
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);
}
18 changes: 10 additions & 8 deletions src/go/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,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
5 changes: 2 additions & 3 deletions src/go/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,13 @@ func (handler *Handler) generate_pairing_code() (string, error) {
* send a list of codes which can be turned into QR codes for scanning with the offical app.
*/
func (handler *Handler) handle_qrcode(qrcodes []string) {
var stringBuilder strings.Builder
pairing_code, err := handler.generate_pairing_code()
if err != nil {
purple_error(handler.account, fmt.Sprintf("%#v", err), ERROR_FATAL)
}
qrcode_data := qrcodes[0] // use only first code for now
// TODO: emit events to destroy and update the code in the ui
fmt.Fprintf(&stringBuilder, "Enter pairing code %s or scan this code to log in:\n%s\n", pairing_code, qrcode_data)
var stringBuilder strings.Builder
qrterminal.GenerateHalfBlock(qrcode_data, qrterminal.L, &stringBuilder)
size := purple_get_int(handler.account, C.GOWHATSAPP_QRCODE_SIZE_OPTION, 256)
var png []byte
Expand All @@ -210,7 +209,7 @@ func (handler *Handler) handle_qrcode(qrcodes []string) {
purple_error(handler.account, fmt.Sprintf("%#v", err), ERROR_FATAL)
}
}
purple_display_qrcode(handler.account, stringBuilder.String(), qrcode_data, png)
purple_display_qrcode(handler.account, pairing_code, qrcode_data, stringBuilder.String(), png)
}

/*
Expand Down

0 comments on commit cec0118

Please sign in to comment.