Skip to content
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
12 changes: 12 additions & 0 deletions Adium.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -384,10 +384,12 @@ ADD1E5C0AF00000000000001 /* AVFoundation.framework in Frameworks */ = {isa = PBX
ADD1E5C0DE0000000000F003 /* AIPurpleWhatsAppAccountPlan.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE0000000000F002 /* AIPurpleWhatsAppAccountPlan.m */; };
ADD1E5C0DE00000000000745 /* AIPurpleGenericAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE00000000000744 /* AIPurpleGenericAccount.m */; };
ADD1E5C0DE0000000000C00B /* Teams-small.png in Resources */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE0000000000C00A /* Teams-small.png */; };
ADD1E5C0DE0000000000A00B /* Matrix-small.png in Resources */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE0000000000A00A /* Matrix-small.png */; };
ADD1E5C0DE0000000000E00B /* TeamsPersonal-small.png in Resources */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE0000000000E00A /* TeamsPersonal-small.png */; };
ADD1E5C0DE0000000000E00D /* TeamsPersonal-large.png in Resources */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE0000000000E00C /* TeamsPersonal-large.png */; };
ADD1E5C0DE0000000000E00F /* prpl-eionrobb-msteams-personal.json in Resources */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE0000000000E00E /* prpl-eionrobb-msteams-personal.json */; };
ADD1E5C0DE0000000000C00D /* Teams-large.png in Resources */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE0000000000C00C /* Teams-large.png */; };
ADD1E5C0DE0000000000A00D /* Matrix-large.png in Resources */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE0000000000A00C /* Matrix-large.png */; };
ADD1E5C0DE0000000000C00F /* prpl-eionrobb-msteams.json in Resources */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE0000000000C00E /* prpl-eionrobb-msteams.json */; };
ADD1E5C0DE00000000000748 /* AIPurpleServiceDescriptors.plist in Resources */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE00000000000747 /* AIPurpleServiceDescriptors.plist */; };
3485DB6309EBCE7400232CC4 /* PurpleDefaultsGadu-Gadu.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4B76473F07A07B620021CCD7 /* PurpleDefaultsGadu-Gadu.plist */; };
Expand Down Expand Up @@ -1297,6 +1299,7 @@ ADD1E5C0AF00000000000001 /* AVFoundation.framework in Frameworks */ = {isa = PBX
ADD1E5C0DE0000000000C002 /* libteams.so in Copy Purple Plugins */,
ADD1E5C0DE0000000000E002 /* libteams-personal.so in Copy Purple Plugins */,
ADD1E5C0DE00000000000782 /* libircv3.so in Copy Purple Plugins */,
ADD1E5C0DE0000000000A002 /* libmatrix.so in Copy Purple Plugins */,
);
name = "Copy Purple Plugins";
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -1498,12 +1501,14 @@ ADD1E5C0AF00000000000001 /* AVFoundation.framework in Frameworks */ = {isa = PBX
ADD1E5C0DE0000000000C002 /* libteams.so in Copy Purple Plugins */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE0000000000C001 /* libteams.so */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
ADD1E5C0DE0000000000E002 /* libteams-personal.so in Copy Purple Plugins */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE0000000000E001 /* libteams-personal.so */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
ADD1E5C0DE00000000000782 /* libircv3.so in Copy Purple Plugins */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE00000000000781 /* libircv3.so */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
ADD1E5C0DE0000000000A002 /* libmatrix.so in Copy Purple Plugins */ = {isa = PBXBuildFile; fileRef = ADD1E5C0DE0000000000A001 /* libmatrix.so */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
ADD1E5C0DE00000000000301 /* libtelegram-tdlib.so */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libtelegram-tdlib.so"; path = "PurplePlugins/libtelegram-tdlib.so"; sourceTree = "<group>"; };
ADD1E5C0DE00000000000302 /* libwhatsmeow.so */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libwhatsmeow.so"; path = "PurplePlugins/libwhatsmeow.so"; sourceTree = "<group>"; };
ADD1E5C0DE00000000000F04 /* libsignal-presage.so */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libsignal-presage.so"; path = "PurplePlugins/libsignal-presage.so"; sourceTree = "<group>"; };
ADD1E5C0DE0000000000C001 /* libteams.so */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libteams.so"; path = "PurplePlugins/libteams.so"; sourceTree = "<group>"; };
ADD1E5C0DE0000000000E001 /* libteams-personal.so */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libteams-personal.so"; path = "PurplePlugins/libteams-personal.so"; sourceTree = "<group>"; };
ADD1E5C0DE00000000000781 /* libircv3.so */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libircv3.so"; path = "PurplePlugins/libircv3.so"; sourceTree = "<group>"; };
ADD1E5C0DE0000000000A001 /* libmatrix.so */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libmatrix.so"; path = "PurplePlugins/libmatrix.so"; sourceTree = "<group>"; };
ADD1E5C0DE00000000000201 /* libwebp.7.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libwebp.7.dylib"; path = "Frameworks/libwebp.7.dylib"; sourceTree = "<group>"; };
ADD1E5C0DE00000000000211 /* libsharpyuv.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libsharpyuv.0.dylib"; path = "Frameworks/libsharpyuv.0.dylib"; sourceTree = "<group>"; };
ADD1E5C0DE00000000000221 /* libpng16.16.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libpng16.16.dylib"; path = "Frameworks/libpng16.16.dylib"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1766,10 +1771,12 @@ ADD1E5C0AF00000000000001 /* AVFoundation.framework in Frameworks */ = {isa = PBX
ADD1E5C0DE0000000000F002 /* AIPurpleWhatsAppAccountPlan.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIPurpleWhatsAppAccountPlan.m; path = "Plugins/Purple Service/AIPurpleWhatsAppAccountPlan.m"; sourceTree = "<group>"; };
ADD1E5C0DE00000000000744 /* AIPurpleGenericAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIPurpleGenericAccount.m; path = "Plugins/Purple Service/AIPurpleGenericAccount.m"; sourceTree = "<group>"; };
ADD1E5C0DE0000000000C00A /* Teams-small.png */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = image.png; name = Teams-small.png; path = "Plugins/Purple Service/Teams-small.png"; sourceTree = "<group>"; };
ADD1E5C0DE0000000000A00A /* Matrix-small.png */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = image.png; name = Matrix-small.png; path = "Plugins/Purple Service/Matrix-small.png"; sourceTree = "<group>"; };
ADD1E5C0DE0000000000E00A /* TeamsPersonal-small.png */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = image.png; name = TeamsPersonal-small.png; path = "Plugins/Purple Service/TeamsPersonal-small.png"; sourceTree = "<group>"; };
ADD1E5C0DE0000000000E00C /* TeamsPersonal-large.png */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = image.png; name = TeamsPersonal-large.png; path = "Plugins/Purple Service/TeamsPersonal-large.png"; sourceTree = "<group>"; };
ADD1E5C0DE0000000000E00E /* prpl-eionrobb-msteams-personal.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = prpl-eionrobb-msteams-personal.json; path = "Plugins/Purple Service/Resources/prpl-eionrobb-msteams-personal.json"; sourceTree = "<group>"; };
ADD1E5C0DE0000000000C00C /* Teams-large.png */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = image.png; name = Teams-large.png; path = "Plugins/Purple Service/Teams-large.png"; sourceTree = "<group>"; };
ADD1E5C0DE0000000000A00C /* Matrix-large.png */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = image.png; name = Matrix-large.png; path = "Plugins/Purple Service/Matrix-large.png"; sourceTree = "<group>"; };
ADD1E5C0DE0000000000C00E /* prpl-eionrobb-msteams.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = prpl-eionrobb-msteams.json; path = "Plugins/Purple Service/Resources/prpl-eionrobb-msteams.json"; sourceTree = "<group>"; };
ADD1E5C0DE00000000000746 /* AIPurpleGenericAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIPurpleGenericAccount.h; path = "Plugins/Purple Service/AIPurpleGenericAccount.h"; sourceTree = "<group>"; };
ADD1E5C0DE00000000000747 /* AIPurpleServiceDescriptors.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; name = AIPurpleServiceDescriptors.plist; path = "Plugins/Purple Service/AIPurpleServiceDescriptors.plist"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3190,6 +3197,7 @@ ADD1E5C0AF00000000000001 /* AVFoundation.framework in Frameworks */ = {isa = PBX
ADD1E5C0DE0000000000C001 /* libteams.so */,
ADD1E5C0DE0000000000E001 /* libteams-personal.so */,
ADD1E5C0DE00000000000781 /* libircv3.so */,
ADD1E5C0DE0000000000A001 /* libmatrix.so */,
ADD1E5C0DE00000000000201 /* libwebp.7.dylib */,
ADD1E5C0DE00000000000211 /* libsharpyuv.0.dylib */,
ADD1E5C0DE00000000000221 /* libpng16.16.dylib */,
Expand Down Expand Up @@ -3574,10 +3582,12 @@ ADD1E5C0AF00000000000001 /* AVFoundation.framework in Frameworks */ = {isa = PBX
ADD1E5C0DE0000000000F002 /* AIPurpleWhatsAppAccountPlan.m */,
ADD1E5C0DE00000000000744 /* AIPurpleGenericAccount.m */,
ADD1E5C0DE0000000000C00A /* Teams-small.png */,
ADD1E5C0DE0000000000A00A /* Matrix-small.png */,
ADD1E5C0DE0000000000E00A /* TeamsPersonal-small.png */,
ADD1E5C0DE0000000000E00C /* TeamsPersonal-large.png */,
ADD1E5C0DE0000000000E00E /* prpl-eionrobb-msteams-personal.json */,
ADD1E5C0DE0000000000C00C /* Teams-large.png */,
ADD1E5C0DE0000000000A00C /* Matrix-large.png */,
ADD1E5C0DE0000000000C00E /* prpl-eionrobb-msteams.json */,
ADD1E5C0DE0000000000B009 /* AIPurpleAccountPlan.h */,
ADD1E5C0DE0000000000B00B /* AIPurpleAccountPlan.m */,
Expand Down Expand Up @@ -6724,10 +6734,12 @@ ADD1E5C0AF00000000000001 /* AVFoundation.framework in Frameworks */ = {isa = PBX
ADD1E5C0DE00000000000748 /* AIPurpleServiceDescriptors.plist in Resources */,
ADD1E5C0DE0000000000B016 /* prpl-jabber.json in Resources */,
ADD1E5C0DE0000000000C00B /* Teams-small.png in Resources */,
ADD1E5C0DE0000000000A00B /* Matrix-small.png in Resources */,
ADD1E5C0DE0000000000E00B /* TeamsPersonal-small.png in Resources */,
ADD1E5C0DE0000000000E00D /* TeamsPersonal-large.png in Resources */,
ADD1E5C0DE0000000000E00F /* prpl-eionrobb-msteams-personal.json in Resources */,
ADD1E5C0DE0000000000C00D /* Teams-large.png in Resources */,
ADD1E5C0DE0000000000A00D /* Matrix-large.png in Resources */,
ADD1E5C0DE0000000000C00F /* prpl-eionrobb-msteams.json in Resources */,
ADD1E5C0DE0000000000B018 /* prpl-irc.json in Resources */,
ADD1E5C0DE0000000000B022 /* prpl-simple.json in Resources */,
Expand Down
43 changes: 43 additions & 0 deletions Dependencies/patches/purple-matrix-rs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# purple-matrix-rs

`Dependencies/source` is not under version control, so this file and `build.sh` are the only record
of what `PurplePlugins/libmatrix.so` was built from.

Base revision: `b2fb0ce276e0d84c8495a9a7a1a955251203c052` (tag `v0.2.1`, 2026-10-14) of
<https://github.com/iilonmasc/purple-matrix-rs>, the Matrix protocol plug-in written for this
bundle: a Rust library on the [matrix-rust-sdk](https://github.com/matrix-org/matrix-rust-sdk)
behind a small C file for libpurple. The SDK does sync, rooms and end-to-end encryption; the plug-in
registers as `prpl-matrix`, so the service entry in `AIPurpleServiceDescriptors.plist` and any
account made for the earlier purple-matrix plug-in carry on unchanged.

There is no `adium.patch`. The plug-in is developed against this bundle, and what Adium needs goes
into the plug-in's repository rather than into a patch here; its `spec/` directory records the
decisions, among them the four rules that came out of the purple-matrix branch: closing a window is
not leaving a room, `/leave` is; nothing is echoed locally, the plug-in writes what the server
confirmed; a room reopens from its state when the account is still in it; a bookmark can be made
from an open room.

## What it does, as of 0.2.1

Signing in with an access token (the password field, with "The password is an access token" set in
the account's options, which keeps the token in the keychain); joined rooms as chats with members,
names, topics and the last lines of history; text in both directions, encrypted by the SDK in
encrypted rooms; invitations; `/leave`; bookmarks and reopening. Not yet: password or SSO sign-in,
typing and read receipts, media, creating rooms, presence, device verification and key backup, so
other clients show the device as unverified.

The SDK's stores live under `<purple user dir>/matrix/<account>/` and are the device's encryption
identity, bound to the token's device id. They are not to be deleted while the token stays: other
clients then keep sharing room keys with the old identity. A fresh start is a new token.

## Building

`build.sh` clones the repository at the pin into `Dependencies/source/purple-matrix-rs`, runs its
`ADIUM=<checkout> just plugin`, and copies the result to `PurplePlugins/libmatrix.so`. It needs a
stable Rust toolchain and `just` on the machine; the first Rust build takes a few minutes.

## Licence

The plug-in is GPL-2.0-or-later. The SDK it links in statically is Apache-2.0, which combines with
GPLv3 and not with GPLv2, so the shipped `libmatrix.so` is distributed under GPLv3, like several
other plug-ins in this bundle (see the fork's README, "License").
60 changes: 60 additions & 0 deletions Dependencies/patches/purple-matrix-rs/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/bash
#
# Build purple-matrix-rs for the bundle and install it as PurplePlugins/libmatrix.so.
#
# The plugin lives in its own repository, https://github.com/iilonmasc/purple-matrix-rs: a Rust
# library on the matrix-rust-sdk (sync, rooms, end-to-end encryption) behind a small C file for
# libpurple. Its own `just plugin` recipe links the two into a loadable bundle; with ADIUM set it
# links against the libraries in Frameworks/ directly, the way purple-presage is built here, so the
# result resolves everything inside the bundle and needs no relink afterwards.
#
# The source is not in the repository. It is fetched here, pinned by commit, and checked against the
# pin, so what ships is exactly what was looked at. There is no adium.patch: the plugin is written
# for this bundle in the first place, and whatever Adium needs goes upstream into it.
#
# Needs a stable Rust toolchain (rustup.rs) and `just` (brew install just), besides Xcode's clang.
# The Rust build takes a few minutes the first time; cargo keeps its output under the checkout's
# target/, so later runs are quick.
#
# Usage: build.sh

set -euo pipefail

export MACOSX_DEPLOYMENT_TARGET=13.0

ADIUM="$(cd "$(dirname "$0")/../../.." && pwd)"
SOURCES="$ADIUM/Dependencies/source"
SRC="$SOURCES/purple-matrix-rs"
OUT="$ADIUM/PurplePlugins/libmatrix.so"

MATRIX_RS_URL=https://github.com/iilonmasc/purple-matrix-rs.git
MATRIX_RS_REV=b2fb0ce276e0d84c8495a9a7a1a955251203c052 # v0.2.1

command -v cargo >/dev/null || { echo "cargo not found: install a stable Rust toolchain from https://rustup.rs" >&2; exit 1; }
command -v just >/dev/null || { echo "just not found: brew install just" >&2; exit 1; }

# Clone at the pin, or check that what is there is the pin. A tree at any other commit is an error
# rather than something to silently build.
if [ ! -d "$SRC/.git" ]; then
echo "fetching purple-matrix-rs at ${MATRIX_RS_REV:0:7}"
mkdir -p "$SOURCES"
git clone -q "$MATRIX_RS_URL" "$SRC"
git -C "$SRC" checkout -q "$MATRIX_RS_REV"
fi
head="$(git -C "$SRC" rev-parse HEAD)"
[ "$head" = "$MATRIX_RS_REV" ] || { echo "$SRC is at ${head:0:7}, expected ${MATRIX_RS_REV:0:7}" >&2; exit 1; }

# The recipe builds the Rust library in release profile, compiles c/prpl.c against Frameworks/,
# links the bundle, strips it and signs it ad hoc (the signature Xcode's copy phase keeps).
(cd "$SRC" && ADIUM="$ADIUM" just plugin)

cp "$SRC/plugin/libmatrix.so" "$OUT"

# Anything absolute would load a second copy of something; say so rather than ship it.
if otool -L "$OUT" | tail -n +2 | grep -qE '^[[:space:]]+/(Users|opt|usr/local)/'; then
echo "libmatrix.so links something outside the bundle:" >&2
otool -L "$OUT" >&2
exit 1
fi

echo "installed $OUT ($(du -h "$OUT" | cut -f1))"
4 changes: 3 additions & 1 deletion License.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ version 2 or, at your option, any later version. Its full text is reproduced
below, and it is the licence under which this source tree is offered.

The application that gets built from it is a different question, and this file
used to answer it wrongly. Adium ships about two dozen libraries and six
used to answer it wrongly. Adium ships about two dozen libraries and seven
protocol plug-ins alongside its own code. Several of them are under GPL version
3, and OpenSSL has been under the Apache licence since version 3.0. Apache 2.0
cannot be combined with GPLv2, and GPLv3 code cannot be used under GPLv2
Expand Down Expand Up @@ -46,12 +46,14 @@ naming where the text was taken from.
libpng libpng-2.0 http://www.libpng.org
libpurple GPL-2.0-or-later https://pidgin.im
libwebp BSD-3-Clause https://developers.google.com/speed/webp
matrix-rust-sdk Apache-2.0 https://github.com/matrix-org/matrix-rust-sdk
MMTabBarView BSD-3-Clause https://github.com/MrNoodle/MMTabBarView
openssl Apache-2.0 https://www.openssl.org
opus BSD-3-Clause https://opus-codec.org
opusfile BSD-3-Clause https://opus-codec.org
picomemo ISC https://codeberg.org/pico/picomemo
purple-gowhatsapp GPL-3.0-or-later https://github.com/hoehermann/purple-gowhatsapp
purple-matrix-rs GPL-2.0-or-later https://github.com/iilonmasc/purple-matrix-rs
purple-presage GPL-3.0-or-later https://github.com/hoehermann/purple-presage
purple-teams GPL-3.0 https://github.com/EionRobb/purple-teams
purple2-ircv3 GPL-2.0 https://github.com/EionRobb/purple2-ircv3
Expand Down
15 changes: 15 additions & 0 deletions Plugins/Purple Service/AIPurpleGenericService.m
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,21 @@ - (BOOL)caseSensitive
return sensitive ? [sensitive boolValue] : [super caseSensitive];
}

/*!
* @brief A chat name is kept as typed where the descriptor says names are case sensitive
*
* AIService lowercases every chat name whatever caseSensitive says, and the hand written services
* live with that: XMPP room names are case insensitive by specification, IRC channels likewise. A
* Matrix room id is not, "!2cKIUR…" and "!2ckiur…" are two different rooms, and a bookmark stored
* under the lowercased name opened a chat that no conversation would ever attach to. The hand
* written services are left alone on purpose; Jabber answers caseSensitive YES for its account
* names and would have its room names compared case sensitively too.
*/
- (NSString *)normalizeChatName:(NSString *)inChatName
{
return [self caseSensitive] ? inChatName : [super normalizeChatName:inChatName];
}

- (AIServiceImportance)serviceImportance
{
return [[descriptor objectForKey:@"ServiceImportance"] isEqualToString:@"Primary"] ?
Expand Down
Loading
Loading