diff --git a/.gitignore b/.gitignore index 6ba4ef0..dd73b4c 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ /beeper-imessage /start /.android-ipc-bin +/imgo.h +/imgo.so diff --git a/android-ipc b/android-ffi similarity index 60% rename from android-ipc rename to android-ffi index e4800f0..3dc5816 100755 --- a/android-ipc +++ b/android-ffi @@ -3,6 +3,5 @@ set -e repo_dir=$(dirname $(realpath $0)) pushd $repo_dir > /dev/null LDFLAGS="-X main.Tag=$(git describe --exact-match --tags 2>/dev/null) -X main.Commit=$(git rev-parse HEAD) -X 'main.BuildTime=$(date '+%b %_d %Y, %H:%M:%S')'" -go build -ldflags "$LDFLAGS" -o .android-ipc-bin ./imessage/ipc/ +go build -ldflags "$LDFLAGS" -buildmode=c-shared -o imgo.so ./imessage/ffi/ popd > /dev/null -rlwrap -H "$HOME/.android-ipc_history" $repo_dir/.android-ipc-bin 2> >(zeroparse >&2) | (trap '' INT; jq -c) diff --git a/android/imessage.sh b/android/imessage.sh index 2004228..ab308bb 100755 --- a/android/imessage.sh +++ b/android/imessage.sh @@ -40,7 +40,7 @@ build_imessage() { (set -x; CGO_LDFLAGS="-lm -llog" CGO_ENABLED=1 GOOS=android GOARCH=$GOARCH GOARM=$GOARM \ CC="$NDK_ROOT/toolchains/llvm/prebuilt/$NDK_ARCH/bin/$NDK_TARGET$ANDROID_API-clang" \ - go build -ldflags "$LDFLAGS" -o "$LIB_JNI"/libima.so ./imessage/ipc) + go build -ldflags "$LDFLAGS" -o "$LIB_JNI"/libima.so ./imessage/ffi) } build_imessage armeabi-v7a armv7a-linux-androideabi arm 7 diff --git a/imessage/ipc/bridgeinfo.go b/imessage/ffi/bridgeinfo.go similarity index 100% rename from imessage/ipc/bridgeinfo.go rename to imessage/ffi/bridgeinfo.go diff --git a/imessage/ipc/commands.go b/imessage/ffi/commands.go similarity index 100% rename from imessage/ipc/commands.go rename to imessage/ffi/commands.go diff --git a/imessage/ipc/events.go b/imessage/ffi/events.go similarity index 99% rename from imessage/ipc/events.go rename to imessage/ffi/events.go index 378defe..5146740 100644 --- a/imessage/ipc/events.go +++ b/imessage/ffi/events.go @@ -824,6 +824,10 @@ func handleDelivered(status *direct.MessageDelivered) { } } +type ReqStarted struct { + LoggedIn bool `json:"logged_in"` +} + func handleEvent(evt any) { switch typedEvt := evt.(type) { case *imessage.Message: diff --git a/imessage/ipc/filetransfer.go b/imessage/ffi/filetransfer.go similarity index 100% rename from imessage/ipc/filetransfer.go rename to imessage/ffi/filetransfer.go diff --git a/imessage/ipc/global.go b/imessage/ffi/global.go similarity index 99% rename from imessage/ipc/global.go rename to imessage/ffi/global.go index 652d33d..89bea89 100644 --- a/imessage/ipc/global.go +++ b/imessage/ffi/global.go @@ -43,7 +43,7 @@ import ( "github.com/beeper/imessage/imessage/direct/ids" "github.com/beeper/imessage/imessage/direct/nacserv" "github.com/beeper/imessage/imessage/direct/util/httputil" - "github.com/beeper/imessage/imessage/ipc/imux" + "github.com/beeper/imessage/imessage/ffi/imux" "github.com/beeper/imessage/ipc" "github.com/beeper/imessage/msgconv" ) diff --git a/imessage/ipc/imux/imux.go b/imessage/ffi/imux/imux.go similarity index 100% rename from imessage/ipc/imux/imux.go rename to imessage/ffi/imux/imux.go diff --git a/imessage/ipc/main.go b/imessage/ffi/main.go similarity index 98% rename from imessage/ipc/main.go rename to imessage/ffi/main.go index 8956358..1abcb33 100644 --- a/imessage/ipc/main.go +++ b/imessage/ffi/main.go @@ -16,6 +16,7 @@ package main +import "C" import ( "context" _ "embed" @@ -89,8 +90,11 @@ func analyticsTrackOverIPC(event string, properties map[string]any) error { }) } -func main() { - writer := ipc.NewLockedWriter(os.Stdout) +func main() {} + +//export start +func start() { + writer := ipc.NewLockedWriter(&FFIStdout) zeroconfig.RegisterWriter(writerTypeStdoutIPC, func(config *zeroconfig.WriterConfig) (io.Writer, error) { return writer, nil }) @@ -121,7 +125,7 @@ func main() { } ipcLog := log.With().Str("component", "ipc").Logger() - global.IPC = ipc.NewProcessor(writer, os.Stdin, &ipcLog) + global.IPC = ipc.NewProcessor(writer, FFIStdinReader, &ipcLog) global.IPC.SetHandler(CmdLogin, ipc.TypedHandler(fnLogin)) global.IPC.SetHandler(CmdMessage, ipc.TypedHandler(fnMessage)) global.IPC.SetHandler(CmdMultipartMessage, ipc.TypedHandler(fnMultipartMessage)) @@ -228,7 +232,6 @@ func main() { log.Err(err).Msg("Failed to close database") } log.Info().Msg("Shutdown preparations complete, exiting") - os.Exit(0) } func initialConfigure(ctx context.Context) { diff --git a/imessage/ffi/stdin.go b/imessage/ffi/stdin.go new file mode 100644 index 0000000..0b2be40 --- /dev/null +++ b/imessage/ffi/stdin.go @@ -0,0 +1,41 @@ +// beeper-imessage - A Matrix-iMessage puppeting bridge. +// Copyright (C) 2023 Beeper, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package main + +import "C" +import ( + "io" + "unsafe" +) + +var FFIStdinReader, FFIStdinWriter = io.Pipe() + +// stdin_write is a function which allows C code to write to the fake "stdin" +// buffer. +// +// This function returns the number of bytes written, or -1 if an error +// occurred. +// +//export stdin_write +func stdin_write(data *C.char, n C.int) C.int { + buf := C.GoBytes(unsafe.Pointer(data), n) + written, err := FFIStdinWriter.Write(buf) + if err != nil { + return C.int(-1) + } + return C.int(written) +} diff --git a/imessage/ffi/stdout.c b/imessage/ffi/stdout.c new file mode 100644 index 0000000..f503c0a --- /dev/null +++ b/imessage/ffi/stdout.c @@ -0,0 +1,7 @@ +#include + +typedef void (*stdout_callback_t)(const char *, int); + +void stdout_write(stdout_callback_t callback, const char *data, int n) { + callback(data, n); +} diff --git a/imessage/ffi/stdout.go b/imessage/ffi/stdout.go new file mode 100644 index 0000000..9a1f0ca --- /dev/null +++ b/imessage/ffi/stdout.go @@ -0,0 +1,44 @@ +// beeper-imessage - A Matrix-iMessage puppeting bridge. +// Copyright (C) 2023 Beeper, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package main + +/* +#include + +// stdout_callback is a function pointer to a function that takes a string and +// returns nothing. +typedef void (*stdout_callback_t)(const char*, int); +void stdout_write(stdout_callback_t callback, const char* data, int n); +*/ +import "C" +import "unsafe" + +type ffiStdout struct { + callback C.stdout_callback_t +} + +func (s *ffiStdout) Write(p []byte) (n int, err error) { + C.stdout_write(s.callback, (*C.char)(unsafe.Pointer(&p[0])), C.int(len(p))) + return len(p), nil +} + +var FFIStdout = ffiStdout{} + +//export set_stdout_callback +func set_stdout_callback(callback C.stdout_callback_t) { + FFIStdout.callback = callback +}