Delta Chat Core C-Library
mrchat.c
1 /*******************************************************************************
2  *
3  * Delta Chat Core
4  * Copyright (C) 2017 Björn Petersen
5  * Contact: r10s@b44t.com, http://b44t.com
6  *
7  * This program is free software: you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License as published by the Free Software
9  * Foundation, either version 3 of the License, or (at your option) any later
10  * version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * this program. If not, see http://www.gnu.org/licenses/ .
19  *
20  ******************************************************************************/
21 
22 
23 #include "mrmailbox_internal.h"
24 #include "mrapeerstate.h"
25 #include "mrjob.h"
26 #include "mrsmtp.h"
27 #include "mrimap.h"
28 #include "mrmimefactory.h"
29 
30 
31 int mrchat_update_param__(mrchat_t* ths)
32 {
33  int success = 0;
34  sqlite3_stmt* stmt = mrsqlite3_prepare_v2_(ths->m_mailbox->m_sql, "UPDATE chats SET param=? WHERE id=?");
35  sqlite3_bind_text(stmt, 1, ths->m_param->m_packed, -1, SQLITE_STATIC);
36  sqlite3_bind_int (stmt, 2, ths->m_id);
37  success = sqlite3_step(stmt)==SQLITE_DONE? 1 : 0;
38  sqlite3_finalize(stmt);
39  return success;
40 }
41 
42 
43 static int mrchat_set_from_stmt__(mrchat_t* ths, sqlite3_stmt* row)
44 {
45  int row_offset = 0;
46  const char* draft_text;
47 
48  if( ths == NULL || row == NULL ) {
49  return 0;
50  }
51 
52  mrchat_empty(ths);
53 
54  #define MR_CHAT_FIELDS " c.id,c.type,c.name, c.draft_timestamp,c.draft_txt,c.grpid,c.param,c.archived "
55  ths->m_id = sqlite3_column_int (row, row_offset++); /* the columns are defined in MR_CHAT_FIELDS */
56  ths->m_type = sqlite3_column_int (row, row_offset++);
57  ths->m_name = safe_strdup((char*)sqlite3_column_text (row, row_offset++));
58  ths->m_draft_timestamp = sqlite3_column_int64(row, row_offset++);
59  draft_text = (const char*)sqlite3_column_text (row, row_offset++);
60  ths->m_grpid = safe_strdup((char*)sqlite3_column_text (row, row_offset++));
61  mrparam_set_packed(ths->m_param, (char*)sqlite3_column_text (row, row_offset++));
62  ths->m_archived = sqlite3_column_int (row, row_offset++);
63 
64  /* We leave a NULL-pointer for the very usual situation of "no draft".
65  Also make sure, m_draft_text and m_draft_timestamp are set together */
66  if( ths->m_draft_timestamp && draft_text && draft_text[0] ) {
67  ths->m_draft_text = safe_strdup(draft_text);
68  }
69  else {
70  ths->m_draft_timestamp = 0;
71  }
72 
73  /* correct the title of some special groups */
74  if( ths->m_id == MR_CHAT_ID_DEADDROP ) {
75  free(ths->m_name);
76  ths->m_name = mrstock_str(MR_STR_DEADDROP);
77  }
78  else if( ths->m_id == MR_CHAT_ID_ARCHIVED_LINK ) {
79  free(ths->m_name);
80  char* tempname = mrstock_str(MR_STR_ARCHIVEDCHATS);
81  ths->m_name = mr_mprintf("%s (%i)", tempname, mrmailbox_get_archived_count__(ths->m_mailbox));
82  free(tempname);
83  }
84  else if( ths->m_id == MR_CHAT_ID_STARRED ) {
85  free(ths->m_name);
86  ths->m_name = mrstock_str(MR_STR_STARREDMSGS);
87  }
88 
89  return row_offset; /* success, return the next row offset */
90 }
91 
92 
100 int mrchat_load_from_db__(mrchat_t* ths, uint32_t id)
101 {
102  sqlite3_stmt* stmt;
103 
104  if( ths==NULL ) {
105  return 0;
106  }
107 
108  mrchat_empty(ths);
109 
110  stmt = mrsqlite3_predefine__(ths->m_mailbox->m_sql, SELECT_itndd_FROM_chats_WHERE_i,
111  "SELECT " MR_CHAT_FIELDS " FROM chats c WHERE c.id=?;");
112  sqlite3_bind_int(stmt, 1, id);
113 
114  if( sqlite3_step(stmt) != SQLITE_ROW ) {
115  return 0;
116  }
117 
118  if( !mrchat_set_from_stmt__(ths, stmt) ) {
119  return 0;
120  }
121 
122  return 1;
123 }
124 
125 
135 mrchat_t* mrchat_new(mrmailbox_t* mailbox)
136 {
137  mrchat_t* ths = NULL;
138 
139  if( mailbox == NULL || (ths=calloc(1, sizeof(mrchat_t)))==NULL ) {
140  exit(14); /* cannot allocate little memory, unrecoverable error */
141  }
142 
143  ths->m_mailbox = mailbox;
144  ths->m_type = MR_CHAT_TYPE_UNDEFINED;
145  ths->m_param = mrparam_new();
146 
147  return ths;
148 }
149 
150 
161 {
162  if( chat==NULL ) {
163  return;
164  }
165 
166  mrchat_empty(chat);
167  mrparam_unref(chat->m_param);
168  free(chat);
169 }
170 
171 
182 {
183  if( ths == NULL ) {
184  return;
185  }
186 
187  free(ths->m_name);
188  ths->m_name = NULL;
189 
190  ths->m_draft_timestamp = 0;
191 
192  free(ths->m_draft_text);
193  ths->m_draft_text = NULL;
194 
195  ths->m_type = MR_CHAT_TYPE_UNDEFINED;
196  ths->m_id = 0;
197 
198  free(ths->m_grpid);
199  ths->m_grpid = NULL;
200 
201  mrparam_set_packed(ths->m_param, NULL);
202 }
203 
204 
216 {
217  /* returns either the address or the number of chat members */
218  char* ret = NULL;
219  sqlite3_stmt* stmt;
220 
221  if( chat == NULL ) {
222  return safe_strdup("Err");
223  }
224 
225  if( chat->m_type == MR_CHAT_TYPE_NORMAL )
226  {
227  int r;
228  mrsqlite3_lock(chat->m_mailbox->m_sql);
229 
230  stmt = mrsqlite3_predefine__(chat->m_mailbox->m_sql, SELECT_a_FROM_chats_contacts_WHERE_i,
231  "SELECT c.addr FROM chats_contacts cc "
232  " LEFT JOIN contacts c ON c.id=cc.contact_id "
233  " WHERE cc.chat_id=?;");
234  sqlite3_bind_int(stmt, 1, chat->m_id);
235 
236  r = sqlite3_step(stmt);
237  if( r == SQLITE_ROW ) {
238  ret = safe_strdup((const char*)sqlite3_column_text(stmt, 0));
239  }
240 
241  mrsqlite3_unlock(chat->m_mailbox->m_sql);
242  }
243  else if( chat->m_type == MR_CHAT_TYPE_GROUP )
244  {
245  int cnt = 0;
246  if( chat->m_id == MR_CHAT_ID_DEADDROP )
247  {
248  mrsqlite3_lock(chat->m_mailbox->m_sql);
249 
250  stmt = mrsqlite3_predefine__(chat->m_mailbox->m_sql, SELECT_COUNT_DISTINCT_f_FROM_msgs_WHERE_c,
251  "SELECT COUNT(DISTINCT from_id) FROM msgs WHERE chat_id=?;");
252  sqlite3_bind_int(stmt, 1, chat->m_id);
253  if( sqlite3_step(stmt) == SQLITE_ROW ) {
254  cnt = sqlite3_column_int(stmt, 0);
255  ret = mrstock_str_repl_pl(MR_STR_CONTACT, cnt);
256  }
257 
258  mrsqlite3_unlock(chat->m_mailbox->m_sql);
259  }
260  else
261  {
262  mrsqlite3_lock(chat->m_mailbox->m_sql);
263 
264  cnt = mrmailbox_get_chat_contact_count__(chat->m_mailbox, chat->m_id);
265  ret = mrstock_str_repl_pl(MR_STR_MEMBER, cnt /*SELF is included in group chats (if not removed)*/);
266 
267  mrsqlite3_unlock(chat->m_mailbox->m_sql);
268  }
269  }
270 
271  return ret? ret : safe_strdup("Err");
272 }
273 
274 
275 
An object representing a single mailbox.
Definition: mrmailbox.h:141
void mrchat_unref(mrchat_t *chat)
Free a chat object.
Definition: mrchat.c:160
void mrparam_unref(mrparam_t *param)
Free an parameter list object created eg.
Definition: mrparam.c:90
char * m_draft_text
NULL if unset.
Definition: mrchat.h:57
mrmailbox_t * m_mailbox
!= NULL
Definition: mrchat.h:58
mrparam_t * m_param
!= NULL
Definition: mrchat.h:60
mrparam_t * mrparam_new()
Create new parameter list object.
Definition: mrparam.c:69
int m_archived
1=chat archived, this state should always be shown the UI, eg.
Definition: mrchat.h:59
char * m_name
NULL if unset.
Definition: mrchat.h:55
void mrchat_empty(mrchat_t *ths)
Empty a chat object.
Definition: mrchat.c:181
time_t m_draft_timestamp
0 if there is no draft
Definition: mrchat.h:56
An object representing a single chat in memory.
Definition: mrchat.h:39
char * mrchat_get_subtitle(mrchat_t *chat)
Get a subtitle for a chat.
Definition: mrchat.c:215