diff --git a/src/MTXClient.h b/src/MTXClient.h index 44198e3..0208cfc 100644 --- a/src/MTXClient.h +++ b/src/MTXClient.h @@ -51,6 +51,16 @@ typedef void (^mtx_client_logout_block_t)(id _Nullable exception); typedef void (^mtx_client_room_list_block_t)( OFArray *_Nullable rooms, id _Nullable exception); +/** + * @brief A block called when a room was joined. + * + * @param roomID The room ID that was joined, or nil on error. This can be used + * to get the room ID if a room alias was joined. + * @param exception An exception if joining the room failed + */ +typedef void (^mtx_client_room_join_block_t)(OFString *_Nullable roomID, + id _Nullable exception); + /** * @brief A class that represents a client. */ @@ -124,6 +134,15 @@ typedef void (^mtx_client_room_list_block_t)( * @param block A block to call with the list of joined room */ - (void)fetchRoomListWithBlock: (mtx_client_room_list_block_t)block; + +/** + * @brief Joins the specified room. + * + * @param room The room to join. Either a room ID or a room alias. + * @param block A block to call when the room was joined + */ +- (void)joinRoom: (OFString *)room + block: (mtx_client_room_join_block_t)block; @end OF_ASSUME_NONNULL_END diff --git a/src/MTXClient.m b/src/MTXClient.m index 01037f8..6650444 100644 --- a/src/MTXClient.m +++ b/src/MTXClient.m @@ -24,6 +24,7 @@ #import "MTXRequest.h" #import "MTXFetchRoomListFailedException.h" +#import "MTXJoinRoomFailedException.h" #import "MTXLoginFailedException.h" #import "MTXLogoutFailedException.h" @@ -201,9 +202,9 @@ validateHomeserver(OFURL *homeserver) if (statusCode != 200) { block([MTXLogoutFailedException - exceptionWithClient: self - statusCode: statusCode - response: response]); + exceptionWithStatusCode: statusCode + response: response + client: self]); return; } @@ -227,9 +228,9 @@ validateHomeserver(OFURL *homeserver) if (statusCode != 200) { block(nil, [MTXFetchRoomListFailedException - exceptionWithClient: self - statusCode: statusCode - response: response]); + exceptionWithStatusCode: statusCode + response: response + client: self]); return; } @@ -251,4 +252,39 @@ validateHomeserver(OFURL *homeserver) objc_autoreleasePoolPop(pool); } + +- (void)joinRoom: (OFString *)room + block: (mtx_client_room_join_block_t)block +{ + void *pool = objc_autoreleasePoolPush(); + MTXRequest *request = [self requestWithPath: + [OFString stringWithFormat: @"/_matrix/client/r0/join/%@", room]]; + request.method = OF_HTTP_REQUEST_METHOD_POST; + [request performWithBlock: ^ (mtx_response_t response, int statusCode, + id exception) { + if (exception != nil) { + block(nil, exception); + return; + } + + if (statusCode != 200) { + block(nil, [MTXJoinRoomFailedException + exceptionWithRoom: room + statusCode: statusCode + response: response + client: self]); + return; + } + + OFString *roomID = response[@"room_id"]; + if (![roomID isKindOfClass: OFString.class]) { + block(nil, [OFInvalidServerReplyException exception]); + return; + } + + block(roomID, nil); + }]; + + objc_autoreleasePoolPop(pool); +} @end diff --git a/src/exceptions/MTXClientException.h b/src/exceptions/MTXClientException.h index 4dad4ad..40ed907 100644 --- a/src/exceptions/MTXClientException.h +++ b/src/exceptions/MTXClientException.h @@ -29,16 +29,17 @@ OF_ASSUME_NONNULL_BEGIN @class MTXClient; @interface MTXClientException: OFException -@property (readonly, nonatomic) MTXClient *client; @property (readonly, nonatomic) int statusCode; @property (readonly, nonatomic) mtx_response_t response; +@property (readonly, nonatomic) MTXClient *client; -+ (instancetype)exceptionWithClient: (MTXClient *)client - statusCode: (int)statusCode - response: (mtx_response_t)response; -- (instancetype)initWithClient: (OFString *)user - statusCode: (int)statusCode - response: (mtx_response_t)response; ++ (instancetype)exceptionWithStatusCode: (int)statusCode + response: (mtx_response_t)response + client: (MTXClient *)client; +- (instancetype)initWithStatusCode: (int)statusCode + response: (mtx_response_t)respons + client: (MTXClient *)client + OF_DESIGNATED_INITIALIZER; @end OF_ASSUME_NONNULL_END diff --git a/src/exceptions/MTXClientException.m b/src/exceptions/MTXClientException.m index b6bae8d..698eb8f 100644 --- a/src/exceptions/MTXClientException.m +++ b/src/exceptions/MTXClientException.m @@ -25,25 +25,25 @@ #import "MTXClient.h" @implementation MTXClientException -+ (instancetype)exceptionWithClient: (MTXClient *)client - statusCode: (int)statusCode - response: (mtx_response_t)response ++ (instancetype)exceptionWithStatusCode: (int)statusCode + response: (mtx_response_t)response + client: (MTXClient *)client { - return [[[self alloc] initWithClient: client - statusCode: statusCode - response: response] autorelease]; + return [[[self alloc] initWithStatusCode: statusCode + response: response + client: client] autorelease]; } -- (instancetype)initWithClient: (MTXClient *)client - statusCode: (int)statusCode - response: (mtx_response_t)response +- (instancetype)initWithStatusCode: (int)statusCode + response: (mtx_response_t)response + client: (MTXClient *)client { self = [super init]; @try { - _client = [client retain]; _statusCode = statusCode; _response = [response copy]; + _client = [client retain]; } @catch (id e) { [self release]; @throw e; @@ -54,8 +54,8 @@ - (void)dealloc { - [_client release]; [_response release]; + [_client release]; [super dealloc]; } diff --git a/src/exceptions/MTXJoinRoomFailedException.h b/src/exceptions/MTXJoinRoomFailedException.h new file mode 100644 index 0000000..1df9192 --- /dev/null +++ b/src/exceptions/MTXJoinRoomFailedException.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020, Jonathan Schleifer + * + * https://fossil.nil.im/objmatrix + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +#import "MTXClientException.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface MTXJoinRoomFailedException: MTXClientException +@property (readonly, nonatomic) OFString *room; + ++ (instancetype)exceptionWithStatusCode: (int)statusCode + response: (mtx_response_t)response + client: (MTXClient *)client OF_UNAVAILABLE; ++ (instancetype)exceptionWithRoom: (OFString *)room + statusCode: (int)statusCode + response: (mtx_response_t)response + client: (MTXClient *)client; +- (instancetype)initWithStatusCode: (int)statusCode + response: (mtx_response_t)response + client: (MTXClient *)client OF_UNAVAILABLE; +- (instancetype)initWithRoom: (OFString *)room + statusCode: (int)statusCode + response: (mtx_response_t)response + client: (MTXClient *)client; +@end + +OF_ASSUME_NONNULL_END diff --git a/src/exceptions/MTXJoinRoomFailedException.m b/src/exceptions/MTXJoinRoomFailedException.m new file mode 100644 index 0000000..3b83b3b --- /dev/null +++ b/src/exceptions/MTXJoinRoomFailedException.m @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020, Jonathan Schleifer + * + * https://fossil.nil.im/objmatrix + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice is present in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#import "MTXJoinRoomFailedException.h" + +#import "MTXClient.h" + +@implementation MTXJoinRoomFailedException ++ (instancetype)exceptionWithRoom: (OFString *)room + statusCode: (int)statusCode + response: (mtx_response_t)response + client: (MTXClient *)client +{ + return [[[self alloc] initWithRoom: room + statusCode: statusCode + response: response + client: client] autorelease]; +} + +- (instancetype)initWithRoom: (OFString *)room + statusCode: (int)statusCode + response: (mtx_response_t)response + client: (MTXClient *)client +{ + self = [super initWithStatusCode: statusCode + response: response + client: client]; + + @try { + _room = [room copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_room release]; + + [super dealloc]; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"Failed to join room %@ for %@: %@", + _room, self.client.userID, self.response]; +} +@end diff --git a/src/exceptions/Makefile b/src/exceptions/Makefile index 5b569b6..866feec 100644 --- a/src/exceptions/Makefile +++ b/src/exceptions/Makefile @@ -5,6 +5,7 @@ STATIC_LIB_NOINST = ${EXCEPTIONS_A} SRCS = MTXClientException.m \ MTXFetchRoomListFailedException.m \ + MTXJoinRoomFailedException.m \ MTXLoginFailedException.m \ MTXLogoutFailedException.m INCLUDES = ${SRCS:.m=.h} diff --git a/tests/tests.m b/tests/tests.m index b7cff75..5322820 100644 --- a/tests/tests.m +++ b/tests/tests.m @@ -74,6 +74,21 @@ OF_APPLICATION_DELEGATE(Tests) of_log(@"Fetched room list: %@", rooms); + [self joinRoom]; + }]; +} + +- (void)joinRoom +{ + [_client joinRoom: @"#test:nil.im" + block: ^ (OFString *roomID, id exception) { + if (exception != nil) { + of_log(@"Failed to join room: %@", exception); + [OFApplication terminateWithStatus: 1]; + } + + of_log(@"Joined room %@", roomID); + [self logOut]; }]; }