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:
parent
36583a4b3b
commit
43b37aeb60
6 changed files with 246 additions and 1 deletions
|
@ -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) {
|
||||
|
|
|
@ -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
163
src/dc_location.c
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
// --------------------------------------------------------------------
|
||||
|
|
|
@ -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().
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue