ObjMatrix  Check-in [e597cc80e1]

Overview
Comment:Adjust to ObjFW changes
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: e597cc80e1537bae3544bccd7b55dbdf963bc846184521ac9bd0e2e82aa695f0
User & Date: js 2021-04-29 00:32:30
Context
2024-07-15
20:31
Adjust to ObjFW changes check-in: 531eb84cf5 user: js tags: trunk
2021-04-29
00:32
Adjust to ObjFW changes check-in: e597cc80e1 user: js tags: trunk
2020-10-31
19:37
Adjust to ObjFW changes check-in: 6b6fe6d802 user: js tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to extra.mk.in.

1
2
3
4
5
6
7
8
9
10
11
12
13
OBJMATRIX_SHARED_LIB = @OBJMATRIX_SHARED_LIB@
OBJMATRIX_STATIC_LIB = @OBJMATRIX_STATIC_LIB@
OBJMATRIX_FRAMEWORK = @OBJMATRIX_FRAMEWORK@
OBJMATRIX_LIB_MAJOR = 0
OBJMATRIX_LIB_MINOR = 0
OBJMATRIX_LIB_MAJOR_MINOR = ${OBJMATRIX_LIB_MAJOR_MINOR}.${OBJMATRIX_LIB_MINOR}

EXCEPTIONS_A = @EXCEPTIONS_A@
EXCEPTIONS_EXCEPTIONS_A = @EXCEPTIONS_EXCEPTIONS_A@
EXCEPTIONS_EXCEPTIONS_LIB_A = @EXCEPTIONS_EXCEPTIONS_LIB_A@
EXCEPTIONS_LIB_A = @EXCEPTIONS_LIB_A@
LIBOBJMATRIX_DEP = @LIBOBJMATRIX_DEP@
OBJFW_CONFIG = @OBJFW_CONFIG@





|







1
2
3
4
5
6
7
8
9
10
11
12
13
OBJMATRIX_SHARED_LIB = @OBJMATRIX_SHARED_LIB@
OBJMATRIX_STATIC_LIB = @OBJMATRIX_STATIC_LIB@
OBJMATRIX_FRAMEWORK = @OBJMATRIX_FRAMEWORK@
OBJMATRIX_LIB_MAJOR = 0
OBJMATRIX_LIB_MINOR = 0
OBJMATRIX_LIB_MAJOR_MINOR = ${OBJMATRIX_LIB_MAJOR}.${OBJMATRIX_LIB_MINOR}

EXCEPTIONS_A = @EXCEPTIONS_A@
EXCEPTIONS_EXCEPTIONS_A = @EXCEPTIONS_EXCEPTIONS_A@
EXCEPTIONS_EXCEPTIONS_LIB_A = @EXCEPTIONS_EXCEPTIONS_LIB_A@
EXCEPTIONS_LIB_A = @EXCEPTIONS_LIB_A@
LIBOBJMATRIX_DEP = @LIBOBJMATRIX_DEP@
OBJFW_CONFIG = @OBJFW_CONFIG@

Changes to src/MTXClient.h.

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

/**
 * @brief A block called when a new login succeeded or failed.
 *
 * @param client If the login succeeded, the newly created client
 * @param exception If the login failed, an exception
 */
typedef void (^mtx_client_login_block_t)(MTXClient *_Nullable client,
    id _Nullable exception);

/**
 * @brief A block called when the response for an operation was received.
 *
 * @param exception `nil` on success, otherwise an exception
 */
typedef void (^mtx_client_response_block_t)(id _Nullable exception);

/**
 * @brief A block called when an exception occurred during sync.
 *
 * @param exception The exception which occurred during sync
 */
typedef void (^mtx_sync_exception_handler_block_t)(id exception);

/**
 * @brief A block called when the room list was fetched.
 *
 * @param rooms An array of joined rooms, or nil on error
 * @param exception An exception if fetching the room list failed
 */
typedef void (^mtx_client_room_list_block_t)(
    OFArray<OFString *> *_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.
 */
@interface MTXClient: OFObject
/**







|







|






|







|
|








|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

/**
 * @brief A block called when a new login succeeded or failed.
 *
 * @param client If the login succeeded, the newly created client
 * @param exception If the login failed, an exception
 */
typedef void (^MTXClientLoginBlock)(MTXClient *_Nullable client,
    id _Nullable exception);

/**
 * @brief A block called when the response for an operation was received.
 *
 * @param exception `nil` on success, otherwise an exception
 */
typedef void (^MTXClientResponseBlock)(id _Nullable exception);

/**
 * @brief A block called when an exception occurred during sync.
 *
 * @param exception The exception which occurred during sync
 */
typedef void (^MTXSyncExceptionHandlerBlock)(id exception);

/**
 * @brief A block called when the room list was fetched.
 *
 * @param rooms An array of joined rooms, or nil on error
 * @param exception An exception if fetching the room list failed
 */
typedef void (^MTXClientRoomListBlock)(OFArray<OFString *> *_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 (^MTXClientRoomJoinBlock)(OFString *_Nullable roomID,
    id _Nullable exception);

/**
 * @brief A class that represents a client.
 */
@interface MTXClient: OFObject
/**
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
@property (readonly, nonatomic) id <MTXStorage> storage;

/**
 * @brief The timeout for sync requests.
 *
 * Defaults to 5 minutes.
 */
@property (nonatomic) of_time_interval_t syncTimeout;

/**
 * @brief A block to handle exceptions that occurred during sync.
 */
@property (copy, nonatomic)
    mtx_sync_exception_handler_block_t syncExceptionHandler;

/**
 * @brief Creates a new client with the specified access token on the specified
 *	  homeserver.
 *
 * @param userID The user ID for the client
 * @param deviceID The device ID for the client







|




|
<







100
101
102
103
104
105
106
107
108
109
110
111
112

113
114
115
116
117
118
119
@property (readonly, nonatomic) id <MTXStorage> storage;

/**
 * @brief The timeout for sync requests.
 *
 * Defaults to 5 minutes.
 */
@property (nonatomic) OFTimeInterval syncTimeout;

/**
 * @brief A block to handle exceptions that occurred during sync.
 */
@property (copy, nonatomic) MTXSyncExceptionHandlerBlock syncExceptionHandler;


/**
 * @brief Creates a new client with the specified access token on the specified
 *	  homeserver.
 *
 * @param userID The user ID for the client
 * @param deviceID The device ID for the client
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
 * @param storage The storage the client should use
 * @param block A block to call once login succeeded or failed
 */
+ (void)logInWithUser: (OFString *)user
	     password: (OFString *)password
	   homeserver: (OFURL *)homeserver
	      storage: (id <MTXStorage>)storage
		block: (mtx_client_login_block_t)block;

/**
 * @brief Initializes an already allocated client with the specified access
 *	  token on the specified homeserver.
 *
 * @param userID The user ID for the client
 * @param deviceID The device ID for the client







|







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
 * @param storage The storage the client should use
 * @param block A block to call once login succeeded or failed
 */
+ (void)logInWithUser: (OFString *)user
	     password: (OFString *)password
	   homeserver: (OFURL *)homeserver
	      storage: (id <MTXStorage>)storage
		block: (MTXClientLoginBlock)block;

/**
 * @brief Initializes an already allocated client with the specified access
 *	  token on the specified homeserver.
 *
 * @param userID The user ID for the client
 * @param deviceID The device ID for the client
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/**
 * @brief Logs out the device and invalidates the access token.
 *
 * @warning The client can no longer be used after this succeeded!
 *
 * @param block A block to call when logging out succeeded or failed
 */
- (void)logOutWithBlock: (mtx_client_response_block_t)block;

/**
 * @brief Fetches the list of joined rooms.
 *
 * @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;

/**
 * @brief Leaves the specified room.
 *
 * @param roomID The room ID to leave
 * @param block A block to call when the room was left
 */
- (void)leaveRoom: (OFString *)roomID
	    block: (mtx_client_response_block_t)block;

/**
 * @brief Sends the specified message to the specified room ID.
 *
 * @param message The message to send
 * @param roomID The room ID to which to send the message
 * @param block A block to call when the message was sent
 */
- (void)sendMessage: (OFString *)message
	     roomID: (OFString *)roomID
	      block: (mtx_client_response_block_t)block;
@end

OF_ASSUME_NONNULL_END







|






|







|
<







|
<










|



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

200
201
202
203
204
205
206
207

208
209
210
211
212
213
214
215
216
217
218
219
220
221
/**
 * @brief Logs out the device and invalidates the access token.
 *
 * @warning The client can no longer be used after this succeeded!
 *
 * @param block A block to call when logging out succeeded or failed
 */
- (void)logOutWithBlock: (MTXClientResponseBlock)block;

/**
 * @brief Fetches the list of joined rooms.
 *
 * @param block A block to call with the list of joined room
 */
- (void)fetchRoomListWithBlock: (MTXClientRoomListBlock)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: (MTXClientRoomJoinBlock)block;


/**
 * @brief Leaves the specified room.
 *
 * @param roomID The room ID to leave
 * @param block A block to call when the room was left
 */
- (void)leaveRoom: (OFString *)roomID block: (MTXClientResponseBlock)block;


/**
 * @brief Sends the specified message to the specified room ID.
 *
 * @param message The message to send
 * @param roomID The room ID to which to send the message
 * @param block A block to call when the message was sent
 */
- (void)sendMessage: (OFString *)message
	     roomID: (OFString *)roomID
	      block: (MTXClientResponseBlock)block;
@end

OF_ASSUME_NONNULL_END

Changes to src/MTXClient.m.

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
				     storage: storage] autorelease];
}

+ (void)logInWithUser: (OFString *)user
	     password: (OFString *)password
	   homeserver: (OFURL *)homeserver
	      storage: (id <MTXStorage>)storage
		block: (mtx_client_login_block_t)block
{
	void *pool = objc_autoreleasePoolPush();

	validateHomeserver(homeserver);

	MTXRequest *request = [MTXRequest
	    requestWithPath: @"/_matrix/client/r0/login"
		accessToken: nil
		 homeserver: homeserver];
	request.method = OF_HTTP_REQUEST_METHOD_POST;
	request.body = @{
		@"type": @"m.login.password",
		@"identifier": @{
			@"type": @"m.id.user",
			@"user": user
		},
		@"password": password
	};

	[request performWithBlock: ^ (mtx_response_t response, int statusCode,
				       id exception) {
		if (exception != nil) {
			block(nil, exception);
			return;
		}

		if (statusCode != 200) {







|









|









|







65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
				     storage: storage] autorelease];
}

+ (void)logInWithUser: (OFString *)user
	     password: (OFString *)password
	   homeserver: (OFURL *)homeserver
	      storage: (id <MTXStorage>)storage
		block: (MTXClientLoginBlock)block
{
	void *pool = objc_autoreleasePoolPush();

	validateHomeserver(homeserver);

	MTXRequest *request = [MTXRequest
	    requestWithPath: @"/_matrix/client/r0/login"
		accessToken: nil
		 homeserver: homeserver];
	request.method = OFHTTPRequestMethodPost;
	request.body = @{
		@"type": @"m.login.password",
		@"identifier": @{
			@"type": @"m.id.user",
			@"user": user
		},
		@"password": password
	};

	[request performWithBlock: ^ (MTXResponse response, int statusCode,
				       id exception) {
		if (exception != nil) {
			block(nil, exception);
			return;
		}

		if (statusCode != 200) {
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
	    requestWithPath: @"/_matrix/client/r0/sync"];
	unsigned long long timeoutMs = _syncTimeout * 1000;
	OFMutableDictionary<OFString *, OFString *> *query =
	    [OFMutableDictionary dictionaryWithObject: @(timeoutMs).stringValue
					       forKey: @"timeout"];
	query[@"since"] = [_storage nextBatchForDeviceID: _deviceID];
	request.query = query;
	[request performWithBlock: ^ (mtx_response_t response, int statusCode,
				       id exception) {
		if (exception != nil) {
			if (_syncExceptionHandler != NULL)
				_syncExceptionHandler(exception);
			return;
		}








|







213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
	    requestWithPath: @"/_matrix/client/r0/sync"];
	unsigned long long timeoutMs = _syncTimeout * 1000;
	OFMutableDictionary<OFString *, OFString *> *query =
	    [OFMutableDictionary dictionaryWithObject: @(timeoutMs).stringValue
					       forKey: @"timeout"];
	query[@"since"] = [_storage nextBatchForDeviceID: _deviceID];
	request.query = query;
	[request performWithBlock: ^ (MTXResponse response, int statusCode,
				       id exception) {
		if (exception != nil) {
			if (_syncExceptionHandler != NULL)
				_syncExceptionHandler(exception);
			return;
		}

271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
}

- (void)stopSyncLoop
{
	_syncing = false;
}

- (void)logOutWithBlock: (mtx_client_response_block_t)block
{
	void *pool = objc_autoreleasePoolPush();
	MTXRequest *request =
	    [self requestWithPath: @"/_matrix/client/r0/logout"];
	request.method = OF_HTTP_REQUEST_METHOD_POST;
	[request performWithBlock: ^ (mtx_response_t response, int statusCode,
				       id exception) {
		if (exception != nil) {
			block(exception);
			return;
		}

		if (statusCode != 200) {
			block([MTXLogoutFailedException
			    exceptionWithStatusCode: statusCode
					   response: response
					     client: self]);
			return;
		}

		block(nil);
	}];

	objc_autoreleasePoolPop(pool);
}

- (void)fetchRoomListWithBlock: (mtx_client_room_list_block_t)block
{
	void *pool = objc_autoreleasePoolPush();
	MTXRequest *request =
	    [self requestWithPath: @"/_matrix/client/r0/joined_rooms"];
	[request performWithBlock: ^ (mtx_response_t response, int statusCode,
				       id exception) {
		if (exception != nil) {
			block(nil, exception);
			return;
		}

		if (statusCode != 200) {







|




|
|




















|




|







271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
}

- (void)stopSyncLoop
{
	_syncing = false;
}

- (void)logOutWithBlock: (MTXClientResponseBlock)block
{
	void *pool = objc_autoreleasePoolPush();
	MTXRequest *request =
	    [self requestWithPath: @"/_matrix/client/r0/logout"];
	request.method = OFHTTPRequestMethodPost;
	[request performWithBlock: ^ (MTXResponse response, int statusCode,
				       id exception) {
		if (exception != nil) {
			block(exception);
			return;
		}

		if (statusCode != 200) {
			block([MTXLogoutFailedException
			    exceptionWithStatusCode: statusCode
					   response: response
					     client: self]);
			return;
		}

		block(nil);
	}];

	objc_autoreleasePoolPop(pool);
}

- (void)fetchRoomListWithBlock: (MTXClientRoomListBlock)block
{
	void *pool = objc_autoreleasePoolPush();
	MTXRequest *request =
	    [self requestWithPath: @"/_matrix/client/r0/joined_rooms"];
	[request performWithBlock: ^ (MTXResponse response, int statusCode,
				       id exception) {
		if (exception != nil) {
			block(nil, exception);
			return;
		}

		if (statusCode != 200) {
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358

		block(response[@"joined_rooms"], nil);
	}];

	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) {







|
<




|
|







337
338
339
340
341
342
343
344

345
346
347
348
349
350
351
352
353
354
355
356
357

		block(response[@"joined_rooms"], nil);
	}];

	objc_autoreleasePoolPop(pool);
}

- (void)joinRoom: (OFString *)room block: (MTXClientRoomJoinBlock)block

{
	void *pool = objc_autoreleasePoolPush();
	MTXRequest *request = [self requestWithPath:
	    [OFString stringWithFormat: @"/_matrix/client/r0/join/%@", room]];
	request.method = OFHTTPRequestMethodPost;
	[request performWithBlock: ^ (MTXResponse response, int statusCode,
				       id exception) {
		if (exception != nil) {
			block(nil, exception);
			return;
		}

		if (statusCode != 200) {
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393

		block(roomID, nil);
	}];

	objc_autoreleasePoolPop(pool);
}

- (void)leaveRoom: (OFString *)roomID
	    block: (mtx_client_response_block_t)block
{
	void *pool = objc_autoreleasePoolPush();
	MTXRequest *request = [self requestWithPath: [OFString
	    stringWithFormat: @"/_matrix/client/r0/rooms/%@/leave", roomID]];
	request.method = OF_HTTP_REQUEST_METHOD_POST;
	[request performWithBlock: ^ (mtx_response_t response, int statusCode,
				       id exception) {
		if (exception != nil) {
			block(exception);
			return;
		}

		if (statusCode != 200) {







|
<




|
|







371
372
373
374
375
376
377
378

379
380
381
382
383
384
385
386
387
388
389
390
391

		block(roomID, nil);
	}];

	objc_autoreleasePoolPop(pool);
}

- (void)leaveRoom: (OFString *)roomID block: (MTXClientResponseBlock)block

{
	void *pool = objc_autoreleasePoolPush();
	MTXRequest *request = [self requestWithPath: [OFString
	    stringWithFormat: @"/_matrix/client/r0/rooms/%@/leave", roomID]];
	request.method = OFHTTPRequestMethodPost;
	[request performWithBlock: ^ (MTXResponse response, int statusCode,
				       id exception) {
		if (exception != nil) {
			block(exception);
			return;
		}

		if (statusCode != 200) {
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
	}];

	objc_autoreleasePoolPop(pool);
}

- (void)sendMessage: (OFString *)message
	     roomID: (OFString *)roomID
	      block: (mtx_client_response_block_t)block;
{
	void *pool = objc_autoreleasePoolPush();
	OFString *path = [OFString stringWithFormat:
	    @"/_matrix/client/r0/rooms/%@/send/m.room.message", roomID];
	MTXRequest *request = [self requestWithPath: path];
	request.method = OF_HTTP_REQUEST_METHOD_POST;
	request.body = @{
		@"msgtype": @"m.text",
		@"body": message
	};
	[request performWithBlock: ^ (mtx_response_t response, int statusCode,
				       id exception) {
		if (exception != nil) {
			block(exception);
			return;
		}

		if (statusCode != 200) {







|





|




|







401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
	}];

	objc_autoreleasePoolPop(pool);
}

- (void)sendMessage: (OFString *)message
	     roomID: (OFString *)roomID
	      block: (MTXClientResponseBlock)block;
{
	void *pool = objc_autoreleasePoolPush();
	OFString *path = [OFString stringWithFormat:
	    @"/_matrix/client/r0/rooms/%@/send/m.room.message", roomID];
	MTXRequest *request = [self requestWithPath: path];
	request.method = OFHTTPRequestMethodPost;
	request.body = @{
		@"msgtype": @"m.text",
		@"body": message
	};
	[request performWithBlock: ^ (MTXResponse response, int statusCode,
				       id exception) {
		if (exception != nil) {
			block(exception);
			return;
		}

		if (statusCode != 200) {
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488

- (void)processJoinedRooms: (OFDictionary<OFString *, id> *)rooms
{
	if (rooms == nil)
		return;

	for (OFString *roomID in rooms)
		[_storage addJoinedRoom: roomID
				forUser: _userID];
}

- (void)processInvitedRooms: (OFDictionary<OFString *, id> *)rooms
{
	if (rooms == nil)
		return;
}

- (void)processLeftRooms: (OFDictionary<OFString *, id> *)rooms
{
	if (rooms == nil)
		return;

	for (OFString *roomID in rooms)
		[_storage removeJoinedRoom: roomID
				   forUser: _userID];
}
@end







|
<














|
<


460
461
462
463
464
465
466
467

468
469
470
471
472
473
474
475
476
477
478
479
480
481
482

483
484

- (void)processJoinedRooms: (OFDictionary<OFString *, id> *)rooms
{
	if (rooms == nil)
		return;

	for (OFString *roomID in rooms)
		[_storage addJoinedRoom: roomID forUser: _userID];

}

- (void)processInvitedRooms: (OFDictionary<OFString *, id> *)rooms
{
	if (rooms == nil)
		return;
}

- (void)processLeftRooms: (OFDictionary<OFString *, id> *)rooms
{
	if (rooms == nil)
		return;

	for (OFString *roomID in rooms)
		[_storage removeJoinedRoom: roomID forUser: _userID];

}
@end

Changes to src/MTXRequest.h.

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
OF_ASSUME_NONNULL_BEGIN

/**
 * @brief A response to a request.
 *
 * This is a typedef for `OFDictionary<OFString *, id> *`.
 */
typedef OFDictionary<OFString *, id> *mtx_response_t;

/**
 * @brief A block called with the response for an MTXRequest.
 *
 * @param response The response to the request, as a dictionary parsed from JSON
 * @param statusCode The HTTP status code returned for the request
 * @param exception The first exception that occurred during the request,
 *		    or `nil` on success
 */
typedef void (^mtx_request_block_t)(mtx_response_t _Nullable response,
    int statusCode, id _Nullable exception);

/**
 * @brief An internal class for performing a request on the Matrix server.
 */
@interface MTXRequest: OFObject <OFHTTPClientDelegate>
/**
 * @brief The access token to use.







|









|
|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
OF_ASSUME_NONNULL_BEGIN

/**
 * @brief A response to a request.
 *
 * This is a typedef for `OFDictionary<OFString *, id> *`.
 */
typedef OFDictionary<OFString *, id> *MTXResponse;

/**
 * @brief A block called with the response for an MTXRequest.
 *
 * @param response The response to the request, as a dictionary parsed from JSON
 * @param statusCode The HTTP status code returned for the request
 * @param exception The first exception that occurred during the request,
 *		    or `nil` on success
 */
typedef void (^MTXRequestBlock)(MTXResponse _Nullable response, int statusCode,
    id _Nullable exception);

/**
 * @brief An internal class for performing a request on the Matrix server.
 */
@interface MTXRequest: OFObject <OFHTTPClientDelegate>
/**
 * @brief The access token to use.
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
@property (readonly, nonatomic) OFURL *homeserver;

/**
 * @brief The HTTP request method.
 *
 * Defaults to `OF_HTTP_REQUEST_METHOD_GET`.
 */
@property (nonatomic) of_http_request_method_t method;

/**
 * @brief The path of the request.
 */
@property (copy, nonatomic) OFString *path;

/**







|







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
@property (readonly, nonatomic) OFURL *homeserver;

/**
 * @brief The HTTP request method.
 *
 * Defaults to `OF_HTTP_REQUEST_METHOD_GET`.
 */
@property (nonatomic) OFHTTPRequestMethod method;

/**
 * @brief The path of the request.
 */
@property (copy, nonatomic) OFString *path;

/**
108
109
110
111
112
113
114
115
116
117
118

/**
 * @brief Performs the request and calls the specified block once the request
 *	  succeeded or failed.
 *
 * @param block The block to call once the request succeeded or failed
 */
- (void)performWithBlock: (mtx_request_block_t)block;
@end

OF_ASSUME_NONNULL_END







|



108
109
110
111
112
113
114
115
116
117
118

/**
 * @brief Performs the request and calls the specified block once the request
 *	  succeeded or failed.
 *
 * @param block The block to call once the request succeeded or failed
 */
- (void)performWithBlock: (MTXRequestBlock)block;
@end

OF_ASSUME_NONNULL_END

Changes to src/MTXRequest.m.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 */

#import "MTXRequest.h"

@implementation MTXRequest
{
	OFData *_body;
	mtx_request_block_t _block;
}

+ (instancetype)requestWithPath: (OFString *)path
		    accessToken: (OFString *)accessToken
		     homeserver: (OFURL *)homeserver
{
	return [[[self alloc] initWithPath: path







|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 */

#import "MTXRequest.h"

@implementation MTXRequest
{
	OFData *_body;
	MTXRequestBlock _block;
}

+ (instancetype)requestWithPath: (OFString *)path
		    accessToken: (OFString *)accessToken
		     homeserver: (OFURL *)homeserver
{
	return [[[self alloc] initWithPath: path
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
{
	self = [super init];

	@try {
		_accessToken = [accessToken copy];
		_homeserver = [homeserver copy];
		_path = [path copy];
		_method = OF_HTTP_REQUEST_METHOD_GET;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
{
	self = [super init];

	@try {
		_accessToken = [accessToken copy];
		_homeserver = [homeserver copy];
		_path = [path copy];
		_method = OFHTTPRequestMethodGet;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
- (void)setBody: (OFDictionary<OFString *, id> *)body
{
	void *pool = objc_autoreleasePoolPush();

	[_body release];

	OFString *JSONString = [body JSONRepresentation];
	_body = [[OFData alloc]
	    initWithItems: JSONString.UTF8String
		    count: JSONString.UTF8StringLength];

	objc_autoreleasePoolPop(pool);
}

- (OFDictionary<OFString *, id> *)body
{
	return [OFString stringWithUTF8String: _body.items
				       length: _body.count]
	    .objectByParsingJSON;
}

- (void)performWithBlock: (mtx_request_block_t)block
{
	void *pool = objc_autoreleasePoolPush();

	if (_block != nil)
		/* Not the best exception to indicate it's already in-flight. */
		@throw [OFAlreadyConnectedException exception];








|
<
|







|
<


|







69
70
71
72
73
74
75
76

77
78
79
80
81
82
83
84
85

86
87
88
89
90
91
92
93
94
95
- (void)setBody: (OFDictionary<OFString *, id> *)body
{
	void *pool = objc_autoreleasePoolPush();

	[_body release];

	OFString *JSONString = [body JSONRepresentation];
	_body = [[OFData alloc] initWithItems: JSONString.UTF8String

					count: JSONString.UTF8StringLength];

	objc_autoreleasePoolPop(pool);
}

- (OFDictionary<OFString *, id> *)body
{
	return [OFString stringWithUTF8String: _body.items
				       length: _body.count].objectByParsingJSON;

}

- (void)performWithBlock: (MTXRequestBlock)block
{
	void *pool = objc_autoreleasePoolPush();

	if (_block != nil)
		/* Not the best exception to indicate it's already in-flight. */
		@throw [OFAlreadyConnectedException exception];

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
	  exception: (id)exception
{
	if (response != nil &&
	    [exception isKindOfClass: [OFHTTPRequestFailedException class]])
		exception = nil;

	/* Reset to nil first, so that another one can be performed. */
	mtx_request_block_t block = _block;
	_block = nil;

	if (exception == nil) {
		@try {
			OFMutableData *responseData = [OFMutableData data];
			while (!response.atEndOfStream) {
				char buffer[512];
				size_t length = [response readIntoBuffer: buffer
								  length: 512];

				[responseData addItems: buffer
						 count: length];
			}

			mtx_response_t responseJSON = [OFString
			    stringWithUTF8String: responseData.items
					  length: responseData.count]
			    .objectByParsingJSON;

			block(responseJSON, response.statusCode, nil);
		} @catch (id e) {
			block(nil, response.statusCode, e);







|










|
<


|







125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143

144
145
146
147
148
149
150
151
152
153
	  exception: (id)exception
{
	if (response != nil &&
	    [exception isKindOfClass: [OFHTTPRequestFailedException class]])
		exception = nil;

	/* Reset to nil first, so that another one can be performed. */
	MTXRequestBlock block = _block;
	_block = nil;

	if (exception == nil) {
		@try {
			OFMutableData *responseData = [OFMutableData data];
			while (!response.atEndOfStream) {
				char buffer[512];
				size_t length = [response readIntoBuffer: buffer
								  length: 512];

				[responseData addItems: buffer count: length];

			}

			MTXResponse responseJSON = [OFString
			    stringWithUTF8String: responseData.items
					  length: responseData.count]
			    .objectByParsingJSON;

			block(responseJSON, response.statusCode, nil);
		} @catch (id e) {
			block(nil, response.statusCode, e);

Changes to src/MTXSQLite3Storage.m.

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
	    @"CREATE TABLE IF NOT EXISTS joined_rooms (\n"
	    @"    user_id TEXT,\n"
	    @"    room_id TEXT,\n"
	    @"    PRIMARY KEY (user_id, room_id)\n"
	    @");"];
}

- (void)transactionWithBlock: (mtx_storage_transaction_block_t)block
{
	[_conn transactionWithBlock: block];
}

- (void)setNextBatch: (OFString *)nextBatch
	 forDeviceID: (OFString *)deviceID
{
	void *pool = objc_autoreleasePoolPush();

	[_nextBatchSetStatement reset];
	[_nextBatchSetStatement bindWithDictionary: @{
		@"$device_id": deviceID,
		@"$next_batch": nextBatch







|




|
<







102
103
104
105
106
107
108
109
110
111
112
113
114

115
116
117
118
119
120
121
	    @"CREATE TABLE IF NOT EXISTS joined_rooms (\n"
	    @"    user_id TEXT,\n"
	    @"    room_id TEXT,\n"
	    @"    PRIMARY KEY (user_id, room_id)\n"
	    @");"];
}

- (void)transactionWithBlock: (MTXStorageTransactionBlock)block
{
	[_conn transactionWithBlock: block];
}

- (void)setNextBatch: (OFString *)nextBatch forDeviceID: (OFString *)deviceID

{
	void *pool = objc_autoreleasePoolPush();

	[_nextBatchSetStatement reset];
	[_nextBatchSetStatement bindWithDictionary: @{
		@"$device_id": deviceID,
		@"$next_batch": nextBatch
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
	    [_nextBatchGetStatement.rowDictionary[@"next_batch"] retain];

	objc_autoreleasePoolPop(pool);

	return [nextBatch autorelease];
}

- (void)addJoinedRoom: (OFString *)roomID
	      forUser: (OFString *)userID
{
	void *pool = objc_autoreleasePoolPush();

	[_joinedRoomsAddStatement reset];
	[_joinedRoomsAddStatement bindWithDictionary: @{
		@"$room_id": roomID,
		@"$user_id": userID
	}];
	[_joinedRoomsAddStatement step];

	objc_autoreleasePoolPop(pool);
}

- (void)removeJoinedRoom: (OFString *)roomID
		 forUser: (OFString *)userID
{
	void *pool = objc_autoreleasePoolPush();

	[_joinedRoomsRemoveStatement reset];
	[_joinedRoomsRemoveStatement bindWithDictionary: @{
		@"$room_id": roomID,
		@"$user_id": userID
	}];
	[_joinedRoomsRemoveStatement step];

	objc_autoreleasePoolPop(pool);
}

- (OFArray<OFString *> *)joinedRoomsForUser: (OFString *)userID
{
	OFMutableArray *joinedRooms = [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();

	[_joinedRoomsGetStatement reset];
	[_joinedRoomsGetStatement bindWithDictionary: @{
		@"$user_id": userID
	}];

	while ([_joinedRoomsGetStatement step])
		[joinedRooms addObject:
		    _joinedRoomsGetStatement.rowDictionary[@"room_id"]];

	objc_autoreleasePoolPop(pool);

	return [joinedRooms autorelease];
}
@end







|
<













|
<



















|
<
<










141
142
143
144
145
146
147
148

149
150
151
152
153
154
155
156
157
158
159
160
161
162

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182


183
184
185
186
187
188
189
190
191
192
	    [_nextBatchGetStatement.rowDictionary[@"next_batch"] retain];

	objc_autoreleasePoolPop(pool);

	return [nextBatch autorelease];
}

- (void)addJoinedRoom: (OFString *)roomID forUser: (OFString *)userID

{
	void *pool = objc_autoreleasePoolPush();

	[_joinedRoomsAddStatement reset];
	[_joinedRoomsAddStatement bindWithDictionary: @{
		@"$room_id": roomID,
		@"$user_id": userID
	}];
	[_joinedRoomsAddStatement step];

	objc_autoreleasePoolPop(pool);
}

- (void)removeJoinedRoom: (OFString *)roomID forUser: (OFString *)userID

{
	void *pool = objc_autoreleasePoolPush();

	[_joinedRoomsRemoveStatement reset];
	[_joinedRoomsRemoveStatement bindWithDictionary: @{
		@"$room_id": roomID,
		@"$user_id": userID
	}];
	[_joinedRoomsRemoveStatement step];

	objc_autoreleasePoolPop(pool);
}

- (OFArray<OFString *> *)joinedRoomsForUser: (OFString *)userID
{
	OFMutableArray *joinedRooms = [OFMutableArray array];
	void *pool = objc_autoreleasePoolPush();

	[_joinedRoomsGetStatement reset];
	[_joinedRoomsGetStatement bindWithDictionary: @{ @"$user_id": userID }];



	while ([_joinedRoomsGetStatement step])
		[joinedRooms addObject:
		    _joinedRoomsGetStatement.rowDictionary[@"room_id"]];

	objc_autoreleasePoolPop(pool);

	return [joinedRooms autorelease];
}
@end

Changes to src/MTXStorage.h.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

/**
 * @brief A block which will be treated as a single transaction for the storage.
 *
 * @return Whether the transaction should be committed (`true`) or rolled back
 *	   (`false`).
 */
typedef bool (^mtx_storage_transaction_block_t)(void);

/**
 * @brief A protocol for a storage to be used by @ref MTXClient.
 */
@protocol MTXStorage <OFObject>
/**
 * @brief Performs all operations inside the block as a transaction.
 */
- (void)transactionWithBlock: (mtx_storage_transaction_block_t)block;

/**
 * @brief Stores the next batch for the specified device.
 *
 * @param nextBatch The next batch for the device
 * @param deviceID The device for which to store the next batch
 */
- (void)setNextBatch: (OFString *)nextBatch
	 forDeviceID: (OFString *)deviceID;

/**
 * @brief Returns the next batch for the specified device.
 *
 * @param deviceID The device ID for which to return the next batch
 * @return The next batch for the specified device, or `nil` if none is
 *	   available.
 */
- (nullable OFString *)nextBatchForDeviceID: (OFString *)deviceID;

/**
 * @brief Adds the specified room ID to the list of joined rooms for the
 *	  specified user ID.
 *
 * @param roomID The room ID to add to the list of joined rooms
 * @param userID The user ID for which to add the room
 */
- (void)addJoinedRoom: (OFString *)roomID
	      forUser: (OFString *)userID;

/**
 * @brief Removes the specified room ID to the list of joined rooms for the
 *	  specified user ID.
 *
 * @param roomID The room ID to add to the list of joined rooms
 * @param userID The user ID for which to add the room
 */
- (void)removeJoinedRoom: (OFString *)roomID
		 forUser: (OFString *)userID;

/**
 * @brief Returns the joined room IDs for the specified user ID.
 *
 * @param userID The user ID for which to return the joined rooms
 * @return The joined room IDs for the specified user ID
 */
- (OFArray<OFString *> *)joinedRoomsForUser: (OFString *)userID;
@end

OF_ASSUME_NONNULL_END







|








|







|
<

















|
<








|
<











26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85
86
87
88

/**
 * @brief A block which will be treated as a single transaction for the storage.
 *
 * @return Whether the transaction should be committed (`true`) or rolled back
 *	   (`false`).
 */
typedef bool (^MTXStorageTransactionBlock)(void);

/**
 * @brief A protocol for a storage to be used by @ref MTXClient.
 */
@protocol MTXStorage <OFObject>
/**
 * @brief Performs all operations inside the block as a transaction.
 */
- (void)transactionWithBlock: (MTXStorageTransactionBlock)block;

/**
 * @brief Stores the next batch for the specified device.
 *
 * @param nextBatch The next batch for the device
 * @param deviceID The device for which to store the next batch
 */
- (void)setNextBatch: (OFString *)nextBatch forDeviceID: (OFString *)deviceID;


/**
 * @brief Returns the next batch for the specified device.
 *
 * @param deviceID The device ID for which to return the next batch
 * @return The next batch for the specified device, or `nil` if none is
 *	   available.
 */
- (nullable OFString *)nextBatchForDeviceID: (OFString *)deviceID;

/**
 * @brief Adds the specified room ID to the list of joined rooms for the
 *	  specified user ID.
 *
 * @param roomID The room ID to add to the list of joined rooms
 * @param userID The user ID for which to add the room
 */
- (void)addJoinedRoom: (OFString *)roomID forUser: (OFString *)userID;


/**
 * @brief Removes the specified room ID to the list of joined rooms for the
 *	  specified user ID.
 *
 * @param roomID The room ID to add to the list of joined rooms
 * @param userID The user ID for which to add the room
 */
- (void)removeJoinedRoom: (OFString *)roomID forUser: (OFString *)userID;


/**
 * @brief Returns the joined room IDs for the specified user ID.
 *
 * @param userID The user ID for which to return the joined rooms
 * @return The joined room IDs for the specified user ID
 */
- (OFArray<OFString *> *)joinedRoomsForUser: (OFString *)userID;
@end

OF_ASSUME_NONNULL_END

Changes to src/exceptions/MTXClientException.h.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

OF_ASSUME_NONNULL_BEGIN

@class MTXClient;

@interface MTXClientException: OFException
@property (readonly, nonatomic) int statusCode;
@property (readonly, nonatomic) mtx_response_t response;
@property (readonly, nonatomic) MTXClient *client;

+ (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







|



|


|





26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

OF_ASSUME_NONNULL_BEGIN

@class MTXClient;

@interface MTXClientException: OFException
@property (readonly, nonatomic) int statusCode;
@property (readonly, nonatomic) MTXResponse response;
@property (readonly, nonatomic) MTXClient *client;

+ (instancetype)exceptionWithStatusCode: (int)statusCode
			       response: (MTXResponse)response
				 client: (MTXClient *)client;
- (instancetype)initWithStatusCode: (int)statusCode
			  response: (MTXResponse)respons
			    client: (MTXClient *)client
    OF_DESIGNATED_INITIALIZER;
@end

OF_ASSUME_NONNULL_END

Changes to src/exceptions/MTXClientException.m.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

#import "MTXLogoutFailedException.h"

#import "MTXClient.h"

@implementation MTXClientException
+ (instancetype)exceptionWithStatusCode: (int)statusCode
			       response: (mtx_response_t)response
				 client: (MTXClient *)client
{
	return [[[self alloc] initWithStatusCode: statusCode
					response: response
					  client: client] autorelease];
}

- (instancetype)initWithStatusCode: (int)statusCode
			  response: (mtx_response_t)response
			    client: (MTXClient *)client
{
	self = [super init];

	@try {
		_statusCode = statusCode;
		_response = [response copy];







|








|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

#import "MTXLogoutFailedException.h"

#import "MTXClient.h"

@implementation MTXClientException
+ (instancetype)exceptionWithStatusCode: (int)statusCode
			       response: (MTXResponse)response
				 client: (MTXClient *)client
{
	return [[[self alloc] initWithStatusCode: statusCode
					response: response
					  client: client] autorelease];
}

- (instancetype)initWithStatusCode: (int)statusCode
			  response: (MTXResponse)response
			    client: (MTXClient *)client
{
	self = [super init];

	@try {
		_statusCode = statusCode;
		_response = [response copy];

Changes to src/exceptions/MTXJoinRoomFailedException.h.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

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







|



|


|



|




26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

OF_ASSUME_NONNULL_BEGIN

@interface MTXJoinRoomFailedException: MTXClientException
@property (readonly, nonatomic) OFString *room;

+ (instancetype)exceptionWithStatusCode: (int)statusCode
			       response: (MTXResponse)response
				 client: (MTXClient *)client OF_UNAVAILABLE;
+ (instancetype)exceptionWithRoom: (OFString *)room
		       statusCode: (int)statusCode
			 response: (MTXResponse)response
			   client: (MTXClient *)client;
- (instancetype)initWithStatusCode: (int)statusCode
			  response: (MTXResponse)response
			    client: (MTXClient *)client OF_UNAVAILABLE;
- (instancetype)initWithRoom: (OFString *)room
		  statusCode: (int)statusCode
		    response: (MTXResponse)response
		      client: (MTXClient *)client;
@end

OF_ASSUME_NONNULL_END

Changes to src/exceptions/MTXJoinRoomFailedException.m.

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#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 {







|










|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#import "MTXJoinRoomFailedException.h"

#import "MTXClient.h"

@implementation MTXJoinRoomFailedException
+ (instancetype)exceptionWithRoom: (OFString *)room
		       statusCode: (int)statusCode
			 response: (MTXResponse)response
			   client: (MTXClient *)client
{
	return [[[self alloc] initWithRoom: room
				statusCode: statusCode
				  response: response
				    client: client] autorelease];
}

- (instancetype)initWithRoom: (OFString *)room
		  statusCode: (int)statusCode
		    response: (MTXResponse)response
		      client: (MTXClient *)client
{
	self = [super initWithStatusCode: statusCode
				response: response
				  client: client];

	@try {

Changes to src/exceptions/MTXLeaveRoomFailedException.h.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

OF_ASSUME_NONNULL_BEGIN

@interface MTXLeaveRoomFailedException: MTXClientException
@property (readonly, nonatomic) OFString *roomID;

+ (instancetype)exceptionWithStatusCode: (int)statusCode
			       response: (mtx_response_t)response
				 client: (MTXClient *)client OF_UNAVAILABLE;
+ (instancetype)exceptionWithRoomID: (OFString *)roomID
			 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)initWithRoomID: (OFString *)roomID
		    statusCode: (int)statusCode
		      response: (mtx_response_t)response
			client: (MTXClient *)client;
@end

OF_ASSUME_NONNULL_END







|



|


|



|




26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

OF_ASSUME_NONNULL_BEGIN

@interface MTXLeaveRoomFailedException: MTXClientException
@property (readonly, nonatomic) OFString *roomID;

+ (instancetype)exceptionWithStatusCode: (int)statusCode
			       response: (MTXResponse)response
				 client: (MTXClient *)client OF_UNAVAILABLE;
+ (instancetype)exceptionWithRoomID: (OFString *)roomID
			 statusCode: (int)statusCode
			   response: (MTXResponse)response
			     client: (MTXClient *)client;
- (instancetype)initWithStatusCode: (int)statusCode
			  response: (MTXResponse)response
			    client: (MTXClient *)client OF_UNAVAILABLE;
- (instancetype)initWithRoomID: (OFString *)roomID
		    statusCode: (int)statusCode
		      response: (MTXResponse)response
			client: (MTXClient *)client;
@end

OF_ASSUME_NONNULL_END

Changes to src/exceptions/MTXLeaveRoomFailedException.m.

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#import "MTXLeaveRoomFailedException.h"

#import "MTXClient.h"

@implementation MTXLeaveRoomFailedException
+ (instancetype)exceptionWithRoomID: (OFString *)roomID
			 statusCode: (int)statusCode
			   response: (mtx_response_t)response
			     client: (MTXClient *)client
{
	return [[[self alloc] initWithRoomID: roomID
				  statusCode: statusCode
				    response: response
				      client: client] autorelease];
}

- (instancetype)initWithRoomID: (OFString *)roomID
		    statusCode: (int)statusCode
		      response: (mtx_response_t)response
			client: (MTXClient *)client
{
	self = [super initWithStatusCode: statusCode
				response: response
				  client: client];

	@try {







|










|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#import "MTXLeaveRoomFailedException.h"

#import "MTXClient.h"

@implementation MTXLeaveRoomFailedException
+ (instancetype)exceptionWithRoomID: (OFString *)roomID
			 statusCode: (int)statusCode
			   response: (MTXResponse)response
			     client: (MTXClient *)client
{
	return [[[self alloc] initWithRoomID: roomID
				  statusCode: statusCode
				    response: response
				      client: client] autorelease];
}

- (instancetype)initWithRoomID: (OFString *)roomID
		    statusCode: (int)statusCode
		      response: (MTXResponse)response
			client: (MTXClient *)client
{
	self = [super initWithStatusCode: statusCode
				response: response
				  client: client];

	@try {

Changes to src/exceptions/MTXLoginFailedException.h.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

OF_ASSUME_NONNULL_BEGIN

@interface MTXLoginFailedException: OFException
@property (readonly, nonatomic) OFString *user;
@property (readonly, nonatomic) OFURL *homeserver;
@property (readonly, nonatomic) int statusCode;
@property (readonly, nonatomic) mtx_response_t response;

+ (instancetype)exceptionWithUser: (OFString *)user
		       homeserver: (OFURL *)homeserver
		       statusCode: (int)statusCode
			 response: (mtx_response_t)response;
- (instancetype)initWithUser: (OFString *)user
		  homeserver: (OFURL *)homeserver
		  statusCode: (int)statusCode
		    response: (mtx_response_t)response;
@end

OF_ASSUME_NONNULL_END







|




|



|



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

OF_ASSUME_NONNULL_BEGIN

@interface MTXLoginFailedException: OFException
@property (readonly, nonatomic) OFString *user;
@property (readonly, nonatomic) OFURL *homeserver;
@property (readonly, nonatomic) int statusCode;
@property (readonly, nonatomic) MTXResponse response;

+ (instancetype)exceptionWithUser: (OFString *)user
		       homeserver: (OFURL *)homeserver
		       statusCode: (int)statusCode
			 response: (MTXResponse)response;
- (instancetype)initWithUser: (OFString *)user
		  homeserver: (OFURL *)homeserver
		  statusCode: (int)statusCode
		    response: (MTXResponse)response;
@end

OF_ASSUME_NONNULL_END

Changes to src/exceptions/MTXLoginFailedException.m.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

#import "MTXLoginFailedException.h"

@implementation MTXLoginFailedException
+ (instancetype)exceptionWithUser: (OFString *)user
		       homeserver: (OFURL *)homeserver
		       statusCode: (int)statusCode
			 response: (mtx_response_t)response
{
	return [[[self alloc] initWithUser: user
				homeserver: homeserver
				statusCode: statusCode
				  response: response] autorelease];
}

- (instancetype)initWithUser: (OFString *)user
		  homeserver: (OFURL *)homeserver
		  statusCode: (int)statusCode
		    response: (mtx_response_t)response
{
	self = [super init];

	@try {
		_user = [user copy];
		_homeserver = [homeserver copy];
		_statusCode = statusCode;







|










|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

#import "MTXLoginFailedException.h"

@implementation MTXLoginFailedException
+ (instancetype)exceptionWithUser: (OFString *)user
		       homeserver: (OFURL *)homeserver
		       statusCode: (int)statusCode
			 response: (MTXResponse)response
{
	return [[[self alloc] initWithUser: user
				homeserver: homeserver
				statusCode: statusCode
				  response: response] autorelease];
}

- (instancetype)initWithUser: (OFString *)user
		  homeserver: (OFURL *)homeserver
		  statusCode: (int)statusCode
		    response: (MTXResponse)response
{
	self = [super init];

	@try {
		_user = [user copy];
		_homeserver = [homeserver copy];
		_statusCode = statusCode;

Changes to src/exceptions/MTXSendMessageFailedException.h.

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
OF_ASSUME_NONNULL_BEGIN

@interface MTXSendMessageFailedException: MTXClientException
@property (readonly, nonatomic) OFString *message;
@property (readonly, nonatomic) OFString *roomID;

+ (instancetype)exceptionWithStatusCode: (int)statusCode
			       response: (mtx_response_t)response
				 client: (MTXClient *)client OF_UNAVAILABLE;
+ (instancetype)exceptionWithMessage: (OFString *)message
			      roomID: (OFString *)roomID
			  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)initWithMessage: (OFString *)message
			 roomID: (OFString *)roomID
		     statusCode: (int)statusCode
		       response: (mtx_response_t)response
			 client: (MTXClient *)client OF_DESIGNATED_INITIALIZER;
@end

OF_ASSUME_NONNULL_END







|




|


|




|




27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
OF_ASSUME_NONNULL_BEGIN

@interface MTXSendMessageFailedException: MTXClientException
@property (readonly, nonatomic) OFString *message;
@property (readonly, nonatomic) OFString *roomID;

+ (instancetype)exceptionWithStatusCode: (int)statusCode
			       response: (MTXResponse)response
				 client: (MTXClient *)client OF_UNAVAILABLE;
+ (instancetype)exceptionWithMessage: (OFString *)message
			      roomID: (OFString *)roomID
			  statusCode: (int)statusCode
			    response: (MTXResponse)response
			      client: (MTXClient *)client;
- (instancetype)initWithStatusCode: (int)statusCode
			  response: (MTXResponse)response
			    client: (MTXClient *)client OF_UNAVAILABLE;
- (instancetype)initWithMessage: (OFString *)message
			 roomID: (OFString *)roomID
		     statusCode: (int)statusCode
		       response: (MTXResponse)response
			 client: (MTXClient *)client OF_DESIGNATED_INITIALIZER;
@end

OF_ASSUME_NONNULL_END

Changes to src/exceptions/MTXSendMessageFailedException.m.

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

#import "MTXClient.h"

@implementation MTXSendMessageFailedException
+ (instancetype)exceptionWithMessage: (OFString *)message
			      roomID: (OFString *)roomID
			  statusCode: (int)statusCode
			    response: (mtx_response_t)response
			      client: (MTXClient *)client
{
	return [[[self alloc] initWithMessage: message
				       roomID: roomID
				   statusCode: statusCode
				     response: response
				       client: client] autorelease];
}

- (instancetype)initWithMessage: (OFString *)message
			 roomID: (OFString *)roomID
		     statusCode: (int)statusCode
		       response: (mtx_response_t)response
			 client: (MTXClient *)client
{
	self = [super initWithStatusCode: statusCode
				response: response
				  client: client];

	@try {







|












|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

#import "MTXClient.h"

@implementation MTXSendMessageFailedException
+ (instancetype)exceptionWithMessage: (OFString *)message
			      roomID: (OFString *)roomID
			  statusCode: (int)statusCode
			    response: (MTXResponse)response
			      client: (MTXClient *)client
{
	return [[[self alloc] initWithMessage: message
				       roomID: roomID
				   statusCode: statusCode
				     response: response
				       client: client] autorelease];
}

- (instancetype)initWithMessage: (OFString *)message
			 roomID: (OFString *)roomID
		     statusCode: (int)statusCode
		       response: (MTXResponse)response
			 client: (MTXClient *)client
{
	self = [super initWithStatusCode: statusCode
				response: response
				  client: client];

	@try {

Changes to tests/tests.m.

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

- (void)applicationDidFinishLaunching
{
	__auto_type environment = OFApplication.environment;
	if (environment[@"OBJMATRIX_USER"] == nil ||
	    environment[@"OBJMATRIX_PASS"] == nil ||
	    environment[@"OBJMATRIX_HS"] == nil) {
		[of_stderr writeString: @"Please set OBJMATRIX_USER, "
					@"OBJMATRIX_PASS and OBJMATRIX_HS in "
					@"the environment!\n"];
		[OFApplication terminateWithStatus: 1];
	}

	OFURL *homeserver = [OFURL URLWithString: environment[@"OBJMATRIX_HS"]];
	id <MTXStorage> storage =
	    [MTXSQLite3Storage storageWithPath: @"tests.db"];
	[MTXClient logInWithUser: environment[@"OBJMATRIX_USER"]
			password: environment[@"OBJMATRIX_PASS"]
		      homeserver: homeserver
			 storage: storage
			   block: ^ (MTXClient *client, id exception) {
		if (exception != nil) {
			of_log(@"Error logging in: %@", exception);
			[OFApplication terminateWithStatus: 1];
		}

		_client = [client retain];
		of_log(@"Logged in client: %@", _client);

		[_client startSyncLoop];
		[self fetchRoomList];
	}];
}

- (void)fetchRoomList
{
	[_client fetchRoomListWithBlock: ^ (OFArray<OFString *> *rooms,
					     id exception) {
		if (exception != nil) {
			of_log(@"Failed to fetch room list: %@", exception);
			[OFApplication terminateWithStatus: 1];
		}

		of_log(@"Fetched room list: %@", rooms);

		[self joinRoom];
	}];
}

- (void)joinRoom
{
	OFString *room = @"#test:nil.im";
	[_client joinRoom: room
		    block: ^ (OFString *roomID, id exception) {
		if (exception != nil) {
			of_log(@"Failed to join room %@: %@", room, exception);
			[OFApplication terminateWithStatus: 1];
		}

		_roomID = [roomID copy];
		of_log(@"Joined room %@", _roomID);

		[self sendMessage];
	}];
}

- (void)sendMessage
{
	[_client sendMessage: @"ObjMatrix test successful!"
		      roomID: _roomID
		       block: ^ (id exception) {
		if (exception != nil) {
			of_log(@"Failed to send message to room %@: %@",
			    _roomID, exception);
			[OFApplication terminateWithStatus: 1];
		}

		of_log(@"Message sent to %@", _roomID);

		of_log(
		    @"Waiting 5 seconds before leaving room and logging out");

		[self performSelector: @selector(leaveRoom)
			   afterDelay: 5];
	}];
}

- (void)leaveRoom
{
	[_client leaveRoom: _roomID
		     block: ^ (id exception) {
		if (exception != nil) {
			of_log(@"Failed to leave room %@: %@", exception);
			[OFApplication terminateWithStatus: 1];
		}

		of_log(@"Left room %@", _roomID);

		[self logOut];
	}];
}

- (void)logOut
{
	[_client logOutWithBlock: ^ (id exception) {
		if (exception != nil) {
			of_log(@"Failed to log out: %@\n", exception);
			[OFApplication terminateWithStatus: 1];
		}

		of_log(@"Logged out client");

		[OFApplication terminate];
	}];
}
@end







|
|
|












|




|











|



|








<
|

|




|











|




|

<
|

|
<





|
<

|



|









|



|





37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

115
116
117

118
119
120
121
122
123

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

- (void)applicationDidFinishLaunching
{
	__auto_type environment = OFApplication.environment;
	if (environment[@"OBJMATRIX_USER"] == nil ||
	    environment[@"OBJMATRIX_PASS"] == nil ||
	    environment[@"OBJMATRIX_HS"] == nil) {
		[OFStdErr writeString: @"Please set OBJMATRIX_USER, "
				       @"OBJMATRIX_PASS and OBJMATRIX_HS in "
				       @"the environment!\n"];
		[OFApplication terminateWithStatus: 1];
	}

	OFURL *homeserver = [OFURL URLWithString: environment[@"OBJMATRIX_HS"]];
	id <MTXStorage> storage =
	    [MTXSQLite3Storage storageWithPath: @"tests.db"];
	[MTXClient logInWithUser: environment[@"OBJMATRIX_USER"]
			password: environment[@"OBJMATRIX_PASS"]
		      homeserver: homeserver
			 storage: storage
			   block: ^ (MTXClient *client, id exception) {
		if (exception != nil) {
			OFLog(@"Error logging in: %@", exception);
			[OFApplication terminateWithStatus: 1];
		}

		_client = [client retain];
		OFLog(@"Logged in client: %@", _client);

		[_client startSyncLoop];
		[self fetchRoomList];
	}];
}

- (void)fetchRoomList
{
	[_client fetchRoomListWithBlock: ^ (OFArray<OFString *> *rooms,
					     id exception) {
		if (exception != nil) {
			OFLog(@"Failed to fetch room list: %@", exception);
			[OFApplication terminateWithStatus: 1];
		}

		OFLog(@"Fetched room list: %@", rooms);

		[self joinRoom];
	}];
}

- (void)joinRoom
{
	OFString *room = @"#test:nil.im";

	[_client joinRoom: room block: ^ (OFString *roomID, id exception) {
		if (exception != nil) {
			OFLog(@"Failed to join room %@: %@", room, exception);
			[OFApplication terminateWithStatus: 1];
		}

		_roomID = [roomID copy];
		OFLog(@"Joined room %@", _roomID);

		[self sendMessage];
	}];
}

- (void)sendMessage
{
	[_client sendMessage: @"ObjMatrix test successful!"
		      roomID: _roomID
		       block: ^ (id exception) {
		if (exception != nil) {
			OFLog(@"Failed to send message to room %@: %@",
			    _roomID, exception);
			[OFApplication terminateWithStatus: 1];
		}

		OFLog(@"Message sent to %@", _roomID);


		OFLog(@"Waiting 5 seconds before leaving room and logging out");

		[self performSelector: @selector(leaveRoom) afterDelay: 5];

	}];
}

- (void)leaveRoom
{
	[_client leaveRoom: _roomID block: ^ (id exception) {

		if (exception != nil) {
			OFLog(@"Failed to leave room %@: %@", exception);
			[OFApplication terminateWithStatus: 1];
		}

		OFLog(@"Left room %@", _roomID);

		[self logOut];
	}];
}

- (void)logOut
{
	[_client logOutWithBlock: ^ (id exception) {
		if (exception != nil) {
			OFLog(@"Failed to log out: %@\n", exception);
			[OFApplication terminateWithStatus: 1];
		}

		OFLog(@"Logged out client");

		[OFApplication terminate];
	}];
}
@end