forked from cory/tildefriends
		
	ssb: Suppress noisy output when running command-line actions with output intended to be parsed.
This commit is contained in:
		@@ -417,9 +417,8 @@ class TfElement extends LitElement {
 | 
				
			|||||||
				ON messages.author = following.value
 | 
									ON messages.author = following.value
 | 
				
			||||||
				GROUP BY messages.author
 | 
									GROUP BY messages.author
 | 
				
			||||||
			`,
 | 
								`,
 | 
				
			||||||
			[
 | 
								[JSON.stringify(Object.keys(users))]
 | 
				
			||||||
				JSON.stringify(Object.keys(users)),
 | 
							);
 | 
				
			||||||
			]);
 | 
					 | 
				
			||||||
		for (let row of info) {
 | 
							for (let row of info) {
 | 
				
			||||||
			users[row.author].seq = row.max_seq;
 | 
								users[row.author].seq = row.max_seq;
 | 
				
			||||||
			users[row.author].ts = row.max_ts;
 | 
								users[row.author].ts = row.max_ts;
 | 
				
			||||||
@@ -459,7 +458,11 @@ class TfElement extends LitElement {
 | 
				
			|||||||
			);
 | 
								);
 | 
				
			||||||
			start_time = new Date();
 | 
								start_time = new Date();
 | 
				
			||||||
			users = await this.fetch_user_info(users);
 | 
								users = await this.fetch_user_info(users);
 | 
				
			||||||
			console.log('user info took', (new Date() - start_time) / 1000.0, 'seconds');
 | 
								console.log(
 | 
				
			||||||
 | 
									'user info took',
 | 
				
			||||||
 | 
									(new Date() - start_time) / 1000.0,
 | 
				
			||||||
 | 
									'seconds'
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
			this.users = users;
 | 
								this.users = users;
 | 
				
			||||||
			console.log(
 | 
								console.log(
 | 
				
			||||||
				`load finished ${whoami} => ${this.whoami} in ${(new Date() - start_time) / 1000}`
 | 
									`load finished ${whoami} => ${this.whoami} in ${(new Date() - start_time) / 1000}`
 | 
				
			||||||
@@ -593,7 +596,8 @@ class TfElement extends LitElement {
 | 
				
			|||||||
				style="position: static; top: 0; z-index: 10"
 | 
									style="position: static; top: 0; z-index: 10"
 | 
				
			||||||
			>
 | 
								>
 | 
				
			||||||
				<button
 | 
									<button
 | 
				
			||||||
					class=${'w3-bar-item w3-button w3-circle w3-ripple' + (this.connections?.some(x => x.flags.one_shot) ? ' w3-spin' : '')}
 | 
										class=${'w3-bar-item w3-button w3-circle w3-ripple' +
 | 
				
			||||||
 | 
										(this.connections?.some((x) => x.flags.one_shot) ? ' w3-spin' : '')}
 | 
				
			||||||
					style="width: 1.5em; height: 1.5em; padding: 8px"
 | 
										style="width: 1.5em; height: 1.5em; padding: 8px"
 | 
				
			||||||
					@click=${this.refresh}
 | 
										@click=${this.refresh}
 | 
				
			||||||
				>
 | 
									>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -275,8 +275,8 @@ class TfTabNewsFeedElement extends LitElement {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	merge_messages(old_messages, new_messages) {
 | 
						merge_messages(old_messages, new_messages) {
 | 
				
			||||||
		let old_by_id = Object.fromEntries(old_messages.map(x => [x.id, x]));
 | 
							let old_by_id = Object.fromEntries(old_messages.map((x) => [x.id, x]));
 | 
				
			||||||
		return new_messages.map(x => old_by_id[x.id] ? old_by_id[x.id] : x);
 | 
							return new_messages.map((x) => (old_by_id[x.id] ? old_by_id[x.id] : x));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	async load_latest() {
 | 
						async load_latest() {
 | 
				
			||||||
@@ -298,14 +298,17 @@ class TfTabNewsFeedElement extends LitElement {
 | 
				
			|||||||
		} finally {
 | 
							} finally {
 | 
				
			||||||
			this.loading--;
 | 
								this.loading--;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		this.messages = this.merge_messages(this.messages, Object.values(
 | 
							this.messages = this.merge_messages(
 | 
				
			||||||
 | 
								this.messages,
 | 
				
			||||||
 | 
								Object.values(
 | 
				
			||||||
				Object.fromEntries(
 | 
									Object.fromEntries(
 | 
				
			||||||
					[...this.messages, ...messages]
 | 
										[...this.messages, ...messages]
 | 
				
			||||||
						.sort((x, y) => x.timestamp - y.timestamp)
 | 
											.sort((x, y) => x.timestamp - y.timestamp)
 | 
				
			||||||
						.slice(-1024)
 | 
											.slice(-1024)
 | 
				
			||||||
						.map((x) => [x.id, x])
 | 
											.map((x) => [x.id, x])
 | 
				
			||||||
				)
 | 
									)
 | 
				
			||||||
		));
 | 
								)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
		console.log('done loading latest messages.');
 | 
							console.log('done loading latest messages.');
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -287,6 +287,7 @@ static int _tf_command_import(const char* file, int argc, char* argv[])
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	_create_directories_for_file(db_path, 0700);
 | 
						_create_directories_for_file(db_path, 0700);
 | 
				
			||||||
	tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
						tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
				
			||||||
 | 
						tf_ssb_set_quiet(ssb, true);
 | 
				
			||||||
	if (optind < argc)
 | 
						if (optind < argc)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		for (int i = optind; i < argc; i++)
 | 
							for (int i = optind; i < argc; i++)
 | 
				
			||||||
@@ -356,6 +357,7 @@ static int _tf_command_export(const char* file, int argc, char* argv[])
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
						tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
				
			||||||
 | 
						tf_ssb_set_quiet(ssb, true);
 | 
				
			||||||
	if (optind < argc)
 | 
						if (optind < argc)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		for (int i = optind; i < argc; i++)
 | 
							for (int i = optind; i < argc; i++)
 | 
				
			||||||
@@ -474,6 +476,7 @@ static int _tf_command_publish(const char* file, int argc, char* argv[])
 | 
				
			|||||||
	tf_printf("Posting %s as account %s belonging to %s...\n", content, identity, user);
 | 
						tf_printf("Posting %s as account %s belonging to %s...\n", content, identity, user);
 | 
				
			||||||
	_create_directories_for_file(db_path, 0700);
 | 
						_create_directories_for_file(db_path, 0700);
 | 
				
			||||||
	tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
						tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
				
			||||||
 | 
						tf_ssb_set_quiet(ssb, true);
 | 
				
			||||||
	uint8_t private_key[512] = { 0 };
 | 
						uint8_t private_key[512] = { 0 };
 | 
				
			||||||
	if (tf_ssb_db_identity_get_private_key(ssb, user, identity, private_key, sizeof(private_key)))
 | 
						if (tf_ssb_db_identity_get_private_key(ssb, user, identity, private_key, sizeof(private_key)))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -579,6 +582,7 @@ static int _tf_command_private(const char* file, int argc, char* argv[])
 | 
				
			|||||||
	tf_printf("Posting %s as account %s belonging to %s...\n", text, identity, user);
 | 
						tf_printf("Posting %s as account %s belonging to %s...\n", text, identity, user);
 | 
				
			||||||
	_create_directories_for_file(db_path, 0700);
 | 
						_create_directories_for_file(db_path, 0700);
 | 
				
			||||||
	tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
						tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
				
			||||||
 | 
						tf_ssb_set_quiet(ssb, true);
 | 
				
			||||||
	uint8_t private_key[512] = { 0 };
 | 
						uint8_t private_key[512] = { 0 };
 | 
				
			||||||
	const char* recipient_list[k_max_private_message_recipients] = { 0 };
 | 
						const char* recipient_list[k_max_private_message_recipients] = { 0 };
 | 
				
			||||||
	int recipient_count = 0;
 | 
						int recipient_count = 0;
 | 
				
			||||||
@@ -728,6 +732,7 @@ static int _tf_command_store_blob(const char* file, int argc, char* argv[])
 | 
				
			|||||||
	char id[256];
 | 
						char id[256];
 | 
				
			||||||
	_create_directories_for_file(db_path, 0700);
 | 
						_create_directories_for_file(db_path, 0700);
 | 
				
			||||||
	tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
						tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
				
			||||||
 | 
						tf_ssb_set_quiet(ssb, true);
 | 
				
			||||||
	if (tf_ssb_db_blob_store(ssb, (const uint8_t*)data, size, id, sizeof(id), NULL))
 | 
						if (tf_ssb_db_blob_store(ssb, (const uint8_t*)data, size, id, sizeof(id), NULL))
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		tf_printf("%s\n", id);
 | 
							tf_printf("%s\n", id);
 | 
				
			||||||
@@ -845,6 +850,7 @@ static int _tf_command_get_sequence(const char* file, int argc, char* argv[])
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
						tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
				
			||||||
 | 
						tf_ssb_set_quiet(ssb, true);
 | 
				
			||||||
	int64_t sequence = -1;
 | 
						int64_t sequence = -1;
 | 
				
			||||||
	int result = tf_ssb_db_get_latest_message_by_author(ssb, identity, &sequence, NULL, 0) ? EXIT_SUCCESS : EXIT_FAILURE;
 | 
						int result = tf_ssb_db_get_latest_message_by_author(ssb, identity, &sequence, NULL, 0) ? EXIT_SUCCESS : EXIT_FAILURE;
 | 
				
			||||||
	tf_printf("%" PRId64 "\n", sequence);
 | 
						tf_printf("%" PRId64 "\n", sequence);
 | 
				
			||||||
@@ -897,6 +903,7 @@ static int _tf_command_get_identity(const char* file, int argc, char* argv[])
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	char id[k_id_base64_len] = { 0 };
 | 
						char id[k_id_base64_len] = { 0 };
 | 
				
			||||||
	tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
						tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
				
			||||||
 | 
						tf_ssb_set_quiet(ssb, true);
 | 
				
			||||||
	int result = tf_ssb_whoami(ssb, id, sizeof(id)) ? EXIT_SUCCESS : EXIT_FAILURE;
 | 
						int result = tf_ssb_whoami(ssb, id, sizeof(id)) ? EXIT_SUCCESS : EXIT_FAILURE;
 | 
				
			||||||
	tf_printf("%s\n", id);
 | 
						tf_printf("%s\n", id);
 | 
				
			||||||
	tf_ssb_destroy(ssb);
 | 
						tf_ssb_destroy(ssb);
 | 
				
			||||||
@@ -1012,6 +1019,7 @@ static int _tf_command_get_contacts(const char* file, int argc, char* argv[])
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
						tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path, NULL);
 | 
				
			||||||
 | 
						tf_ssb_set_quiet(ssb, true);
 | 
				
			||||||
	JSContext* context = tf_ssb_get_context(ssb);
 | 
						JSContext* context = tf_ssb_get_context(ssb);
 | 
				
			||||||
	JSValue contacts = JS_NewObject(context);
 | 
						JSValue contacts = JS_NewObject(context);
 | 
				
			||||||
	JSValue follows = JS_NewObject(context);
 | 
						JSValue follows = JS_NewObject(context);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										32
									
								
								src/ssb.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								src/ssb.c
									
									
									
									
									
								
							@@ -197,6 +197,7 @@ typedef struct _tf_ssb_t
 | 
				
			|||||||
	uint8_t priv[crypto_sign_SECRETKEYBYTES];
 | 
						uint8_t priv[crypto_sign_SECRETKEYBYTES];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool verbose;
 | 
						bool verbose;
 | 
				
			||||||
 | 
						bool quiet;
 | 
				
			||||||
	bool shutting_down;
 | 
						bool shutting_down;
 | 
				
			||||||
	bool shutting_down_deferred;
 | 
						bool shutting_down_deferred;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2532,8 +2533,11 @@ static void _tf_ssb_on_timer_close(uv_handle_t* handle)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void tf_ssb_destroy(tf_ssb_t* ssb)
 | 
					void tf_ssb_destroy(tf_ssb_t* ssb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!ssb->quiet)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		tf_printf("tf_ssb_destroy\n");
 | 
							tf_printf("tf_ssb_destroy\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	ssb->shutting_down = true;
 | 
						ssb->shutting_down = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ssb->broadcast_listener.data && !uv_is_closing((uv_handle_t*)&ssb->broadcast_listener))
 | 
						if (ssb->broadcast_listener.data && !uv_is_closing((uv_handle_t*)&ssb->broadcast_listener))
 | 
				
			||||||
@@ -2576,7 +2580,10 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
 | 
				
			|||||||
		uv_close((uv_handle_t*)&ssb->timers[i]->timer, _tf_ssb_on_timer_close);
 | 
							uv_close((uv_handle_t*)&ssb->timers[i]->timer, _tf_ssb_on_timer_close);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ssb->quiet)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
		tf_printf("Waiting for closes.\n");
 | 
							tf_printf("Waiting for closes.\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (ssb->broadcast_listener.data || ssb->broadcast_sender.data || ssb->broadcast_timer.data || ssb->broadcast_cleanup_timer.data || ssb->trace_timer.data ||
 | 
						while (ssb->broadcast_listener.data || ssb->broadcast_sender.data || ssb->broadcast_timer.data || ssb->broadcast_cleanup_timer.data || ssb->trace_timer.data ||
 | 
				
			||||||
		ssb->server.data || ssb->ref_count || ssb->request_activity_timer.data || ssb->timers_count)
 | 
							ssb->server.data || ssb->ref_count || ssb->request_activity_timer.data || ssb->timers_count)
 | 
				
			||||||
@@ -2584,7 +2591,10 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
 | 
				
			|||||||
		uv_run(ssb->loop, UV_RUN_ONCE);
 | 
							uv_run(ssb->loop, UV_RUN_ONCE);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ssb->quiet)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
		tf_printf("Waiting for rpc.\n");
 | 
							tf_printf("Waiting for rpc.\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (ssb->rpc)
 | 
						while (ssb->rpc)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -2643,7 +2653,10 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
 | 
				
			|||||||
		tf_free(node);
 | 
							tf_free(node);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ssb->quiet)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
		tf_printf("Closing connections.\n");
 | 
							tf_printf("Closing connections.\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	tf_ssb_connection_t* connection = ssb->connections;
 | 
						tf_ssb_connection_t* connection = ssb->connections;
 | 
				
			||||||
	while (connection)
 | 
						while (connection)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -2652,7 +2665,10 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
 | 
				
			|||||||
		connection = next;
 | 
							connection = next;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	uv_run(ssb->loop, UV_RUN_NOWAIT);
 | 
						uv_run(ssb->loop, UV_RUN_NOWAIT);
 | 
				
			||||||
 | 
						if (!ssb->quiet)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
		tf_printf("Closed.\n");
 | 
							tf_printf("Closed.\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ssb->connections_tracker)
 | 
						if (ssb->connections_tracker)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -2663,18 +2679,27 @@ void tf_ssb_destroy(tf_ssb_t* ssb)
 | 
				
			|||||||
	uv_run(ssb->loop, UV_RUN_NOWAIT);
 | 
						uv_run(ssb->loop, UV_RUN_NOWAIT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ssb->loop == &ssb->own_loop)
 | 
						if (ssb->loop == &ssb->own_loop)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!ssb->quiet)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			tf_printf("uv_loop_close\n");
 | 
								tf_printf("uv_loop_close\n");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		int r = uv_loop_close(ssb->loop);
 | 
							int r = uv_loop_close(ssb->loop);
 | 
				
			||||||
		if (r != 0)
 | 
							if (r != 0 && !ssb->quiet)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			tf_printf("uv_loop_close: %s\n", uv_strerror(r));
 | 
								tf_printf("uv_loop_close: %s\n", uv_strerror(r));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (!ssb->quiet)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
		tf_printf("uv loop closed.\n");
 | 
							tf_printf("uv loop closed.\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (ssb->own_context)
 | 
						if (ssb->own_context)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (!ssb->quiet)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			tf_printf("closing ssb context\n");
 | 
								tf_printf("closing ssb context\n");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		JS_FreeContext(ssb->context);
 | 
							JS_FreeContext(ssb->context);
 | 
				
			||||||
		JS_FreeRuntime(ssb->runtime);
 | 
							JS_FreeRuntime(ssb->runtime);
 | 
				
			||||||
		ssb->own_context = false;
 | 
							ssb->own_context = false;
 | 
				
			||||||
@@ -4254,6 +4279,11 @@ void tf_ssb_set_verbose(tf_ssb_t* ssb, bool verbose)
 | 
				
			|||||||
	ssb->verbose = verbose;
 | 
						ssb->verbose = verbose;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void tf_ssb_set_quiet(tf_ssb_t* ssb, bool quiet)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ssb->quiet = quiet;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void _tf_ssb_scheduled_timer(uv_timer_t* handle)
 | 
					static void _tf_ssb_scheduled_timer(uv_timer_t* handle)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	tf_ssb_timer_t* timer = handle->data;
 | 
						tf_ssb_timer_t* timer = handle->data;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -189,6 +189,13 @@ void tf_ssb_start_periodic(tf_ssb_t* ssb);
 | 
				
			|||||||
*/
 | 
					*/
 | 
				
			||||||
void tf_ssb_set_verbose(tf_ssb_t* ssb, bool verbose);
 | 
					void tf_ssb_set_verbose(tf_ssb_t* ssb, bool verbose);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					** Reduce logging verbosity.
 | 
				
			||||||
 | 
					** @param ssb The SSB instance.
 | 
				
			||||||
 | 
					** @param quiet Disable unnecessary messages.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void tf_ssb_set_quiet(tf_ssb_t* ssb, bool quiet);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
** Acquire an SQLite database for unrestricted reading.  Release qith tf_ssb_release_db_reader().
 | 
					** Acquire an SQLite database for unrestricted reading.  Release qith tf_ssb_release_db_reader().
 | 
				
			||||||
** @param ssb The SSB instance.
 | 
					** @param ssb The SSB instance.
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user