1
0
Fork 0
mirror of https://github.com/deltachat/deltachat-core.git synced 2025-10-05 19:42:04 +02:00

send location together with messages

This commit is contained in:
B. Petersen 2019-03-06 00:03:18 +01:00
parent 36583a4b3b
commit 43b37aeb60
No known key found for this signature in database
GPG key ID: 3B88E92DEA8E9AFC
6 changed files with 246 additions and 1 deletions

View file

@ -437,6 +437,8 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline)
"groupname <name>\n"
"groupimage [<file>]\n"
"chatinfo\n"
"sendlocations <seconds>\n"
"setlocation <lat> <lng>\n"
"send <text>\n"
"sendimage <file> [<text>]\n"
"sendfile <file>\n"
@ -885,7 +887,9 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline)
if (contacts) {
dc_log_info(context, 0, "Memberlist:");
log_contactlist(context, contacts);
ret = dc_mprintf("%i contacts.", (int)dc_array_get_cnt(contacts));
ret = dc_mprintf("%i contacts\nLocation streaming: %i",
(int)dc_array_get_cnt(contacts),
dc_is_sending_locations_to_chat(context, dc_chat_get_id(sel_chat)));
}
else {
ret = COMMAND_FAILED;
@ -895,6 +899,36 @@ char* dc_cmdline(dc_context_t* context, const char* cmdline)
ret = dc_strdup("No chat selected.");
}
}
else if (strcmp(cmd, "sendlocations")==0)
{
if (sel_chat) {
if (arg1 && arg1[0]) {
int seconds = atoi(arg1);
dc_send_locations_to_chat(context, dc_chat_get_id(sel_chat), seconds);
ret = COMMAND_SUCCEEDED;
}
else {
ret = dc_strdup("ERROR: No timeout given.");
}
}
else {
ret = dc_strdup("No chat selected.");
}
}
else if (strcmp(cmd, "setlocation")==0) {
char* arg2 = NULL;
if (arg1) { arg2 = strrchr(arg1, ' '); }
if (arg1 && arg2) {
*arg2 = 0; arg2++;
double latitude = atof(arg1);
double longitude = atof(arg2);
dc_set_location(context, latitude, longitude, 0.0);
ret = COMMAND_SUCCEEDED;
}
else {
ret = dc_strdup("ERROR: Latitude or longitude not given.");
}
}
else if (strcmp(cmd, "send")==0)
{
if (sel_chat) {

View file

@ -121,6 +121,8 @@ int dc_is_inbox (dc_context_t*, const char* folder);
int dc_is_sentbox (dc_context_t*, const char* folder);
int dc_is_mvbox (dc_context_t*, const char* folder);
char* dc_get_location_str (dc_context_t*);
#define DC_BAK_PREFIX "delta-chat"
#define DC_BAK_SUFFIX "bak"

163
src/dc_location.c Normal file
View file

@ -0,0 +1,163 @@
#include "dc_context.h"
#include "dc_mimeparser.h"
#include "dc_job.h"
/**
* Enable or disable location streaming for a chat.
* Locations are sent to all members of the chat for the given number of seconds;
* after that, location streaming is automatically disabled for the chat.
* The current location streaming state of a chat
* can be checked using dc_is_sending_locations_to_chat().
*
* The locations that should be sent to the chat can be set using
* dc_set_location().
*
* @memberof dc_context_t
* @param context The context object.
* @param chat_id Chat id to enable location streaming for.
* @param seconds >0: enable location streaming for the given number of seconds;
* 0: disable location streaming.
* @return None.
*/
void dc_send_locations_to_chat(dc_context_t* context, uint32_t chat_id,
int seconds)
{
sqlite3_stmt* stmt = NULL;
if (context==0 || context->magic!=DC_CONTEXT_MAGIC || seconds<0) {
goto cleanup;
}
stmt = dc_sqlite3_prepare(context->sql,
"UPDATE chats "
" SET locations_send_until=? "
" WHERE id=?");
sqlite3_bind_int64(stmt, 1, time(NULL)+seconds);
sqlite3_bind_int (stmt, 2, chat_id);
sqlite3_step(stmt);
// TODO: send a status message
cleanup:
sqlite3_finalize(stmt);
}
/**
* Check if location streaming is enabled for a chat.
* Location stream can be enabled or disabled using dc_send_locations_to_chat().
*
* @memberof dc_context_t
* @param context The context object.
* @param chat_id Chat id to check.
* @return 1: location streaming is enabled for the given chat;
* 0: location streaming is disabled for the given chat.
*/
int dc_is_sending_locations_to_chat(dc_context_t* context, uint32_t chat_id)
{
int is_sending_locations = 0;
sqlite3_stmt* stmt = NULL;
time_t send_until = 0;
if (context==0 || context->magic!=DC_CONTEXT_MAGIC) {
goto cleanup;
}
stmt = dc_sqlite3_prepare(context->sql,
"SELECT locations_send_until "
" FROM chats "
" WHERE id=?");
sqlite3_bind_int(stmt, 1, chat_id);
if (sqlite3_step(stmt)!=SQLITE_ROW) {
goto cleanup;
}
send_until = sqlite3_column_int64(stmt, 0);
if (time(NULL) < send_until) {
is_sending_locations = 1;
}
cleanup:
sqlite3_finalize(stmt);
return is_sending_locations;
}
/**
* Set current location.
* The location is sent to all chats where location streaming is enabled
* using dc_send_locations_to_chat().
*
* @memberof dc_context_t
* @param context The context object.
* @param latitude North-south position of the location.
* Set to 0.0 if the latitude is not known.
* @param longitude East-west position of the location.
* Set to 0.0 if the longitude is not known.
* @param accuracy Estimated accuracy of the location, radial, in meters.
* Set to 0.0 if the accuracy is not known.
* @return 1: location streaming is still enabled for at least one chat,
* this dc_set_location() should be called as soon as the location changes;
* 0: location streaming is no longer needed,
* dc_is_sending_locations_to_chat() is false for all chats.
*/
int dc_set_location(dc_context_t* context,
double latitude, double longitude, double accuracy)
{
sqlite3_stmt* stmt = NULL;
if (context==0 || context->magic!=DC_CONTEXT_MAGIC
|| (latitude==0.0 && longitude==0.0)) {
goto cleanup;
}
stmt = dc_sqlite3_prepare(context->sql,
"INSERT INTO locations "
" (latitude, longitude, accuracy, timestamp, from_id)"
" VALUES (?,?,?,?,?);");
sqlite3_bind_double(stmt, 1, latitude);
sqlite3_bind_double(stmt, 2, longitude);
sqlite3_bind_double(stmt, 3, accuracy);
sqlite3_bind_int64 (stmt, 4, time(NULL));
sqlite3_bind_int (stmt, 5, DC_CONTACT_ID_SELF);
sqlite3_step(stmt);
context->cb(context, DC_EVENT_LOCATION_CHANGED, DC_CONTACT_ID_SELF, 0);
cleanup:
sqlite3_finalize(stmt);
return 1; // TODO: check state
}
char* dc_get_location_str(dc_context_t* context)
{
sqlite3_stmt* stmt = NULL;
double latitude = 0.0;
double longitude = 0.0;
double accuracy = 0.0;
if (context==0 || context->magic!=DC_CONTEXT_MAGIC) {
goto cleanup;
}
stmt = dc_sqlite3_prepare(context->sql,
"SELECT latitude, longitude, accuracy, timestamp "
" FROM locations "
" WHERE from_id=? "
" AND timestamp=(SELECT MAX(timestamp) FROM locations WHERE from_id=?) ");
sqlite3_bind_int (stmt, 1, DC_CONTACT_ID_SELF);
sqlite3_bind_int (stmt, 2, DC_CONTACT_ID_SELF);
if (sqlite3_step(stmt)==SQLITE_ROW) {
latitude = sqlite3_column_double(stmt, 0);
longitude = sqlite3_column_double(stmt, 1);
accuracy = sqlite3_column_double(stmt, 2);
}
cleanup:
sqlite3_finalize(stmt);
return dc_mprintf("%f %f %f", latitude, longitude, accuracy);
}

View file

@ -612,6 +612,12 @@ int dc_mimefactory_render(dc_mimefactory_t* factory)
}
}
if (dc_is_sending_locations_to_chat(msg->context, msg->chat_id)) {
mailimf_fields_add(imf_fields, mailimf_field_new_custom(
strdup("Chat-Location"),
dc_get_location_str(msg->context)));
}
if (grpimage)
{
dc_msg_t* meta = dc_msg_new_untyped(factory->context);

View file

@ -566,6 +566,30 @@ int dc_sqlite3_open(dc_sqlite3_t* sql, const char* dbfile, int flags)
}
#undef NEW_DB_VERSION
#define NEW_DB_VERSION 51
if (dbversion < NEW_DB_VERSION)
{
// the messages containing _only_ locations
// are also added to the database as _hidden_.
dc_sqlite3_execute(sql, "CREATE TABLE locations ("
" id INTEGER PRIMARY KEY,"
" latitude REAL DEFAULT 0.0,"
" longitude REAL DEFAULT 0.0,"
" accuracy REAL DEFAULT 0.0,"
" timestamp INTEGER DEFAULT 0,"
" chat_id INTEGER DEFAULT 0,"
" from_id INTEGER DEFAULT 0,"
" msg_id INTEGER DEFAULT 0);");
dc_sqlite3_execute(sql, "CREATE INDEX locations_index1 ON locations (msg_id);");
dc_sqlite3_execute(sql, "CREATE INDEX locations_index2 ON locations (timestamp);");
dc_sqlite3_execute(sql, "ALTER TABLE chats ADD COLUMN locations_send_until INTEGER DEFAULT 0;");
dc_sqlite3_execute(sql, "ALTER TABLE chats ADD COLUMN locations_last_sent INTEGER DEFAULT 0;");
dbversion = NEW_DB_VERSION;
dc_sqlite3_set_config_int(sql, "dbversion", NEW_DB_VERSION);
}
#undef NEW_DB_VERSION
// (2) updates that require high-level objects
// (the structure is complete now and all objects are usable)
// --------------------------------------------------------------------

View file

@ -360,6 +360,11 @@ char* dc_get_securejoin_qr (dc_context_t*, uint32_t chat_id);
uint32_t dc_join_securejoin (dc_context_t*, const char* qr);
// location streaming
void dc_send_locations_to_chat (dc_context_t*, uint32_t chat_id, int seconds);
int dc_is_sending_locations_to_chat (dc_context_t*, uint32_t chat_id);
int dc_set_location (dc_context_t*, double latitude, double longitude, double accuracy);
/**
* @class dc_array_t
*
@ -985,6 +990,17 @@ time_t dc_lot_get_timestamp (const dc_lot_t*);
#define DC_EVENT_CONTACTS_CHANGED 2030
/**
* Location of one or more contact has changed.
*
* @param data1 (int) contact_id of the contact for which the location has changed.
* @param data2 0
* @return 0
*/
#define DC_EVENT_LOCATION_CHANGED 2035
/**
* Inform about the configuration progress started by dc_configure().
*