1 /*
2 * Calcurse - text-based organizer
3 *
4 * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above
12 * copyright notice, this list of conditions and the
13 * following disclaimer.
14 *
15 * - Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the
17 * following disclaimer in the documentation and/or other
18 * materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * Send your feedback or comments to : misc@calcurse.org
33 * Calcurse home page : http://calcurse.org
34 *
35 */
36
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include "calcurse.h"
42 #include "sha1.h"
43
44 llist_t todolist;
45
todo_is_uncompleted(struct todo * todo,void * cbdata)46 static int todo_is_uncompleted(struct todo *todo, void *cbdata)
47 {
48 return !todo->completed;
49 }
50
51 /* Returns a structure containing the selected item. */
todo_get_item(int item_number,int skip_completed)52 struct todo *todo_get_item(int item_number, int skip_completed)
53 {
54 llist_item_t *i;
55
56 if (skip_completed)
57 i = LLIST_FIND_NTH(&todolist, item_number, NULL,
58 todo_is_uncompleted);
59 else
60 i = LLIST_NTH(&todolist, item_number);
61
62 if (!i)
63 return NULL;
64
65 return LLIST_GET_DATA(i);
66 }
67
todo_cmp(struct todo * a,struct todo * b)68 static int todo_cmp(struct todo *a, struct todo *b)
69 {
70 if (a->completed && !b->completed)
71 return 1;
72 if (b->completed && !a->completed)
73 return -1;
74 if (a->id > 0 && b->id == 0)
75 return -1;
76 if (b->id > 0 && a->id == 0)
77 return 1;
78 if (a->id == b->id)
79 return strcmp(a->mesg, b->mesg);
80
81 return a->id - b->id;
82 }
83
84 /*
85 * Add an item in the todo linked list.
86 */
todo_add(char * mesg,int id,int completed,char * note)87 struct todo *todo_add(char *mesg, int id, int completed, char *note)
88 {
89 struct todo *todo;
90
91 todo = mem_malloc(sizeof(struct todo));
92 todo->mesg = mem_strdup(mesg);
93 todo->id = id;
94 todo->completed = completed;
95 todo->note = (note != NULL
96 && note[0] != '\0') ? mem_strdup(note) : NULL;
97
98 LLIST_ADD_SORTED(&todolist, todo, todo_cmp);
99
100 return todo;
101 }
102
todo_tostr(struct todo * todo)103 char *todo_tostr(struct todo *todo)
104 {
105 char *res;
106 const char *cstr = todo->completed ? "-" : "";
107
108 if (todo->note)
109 asprintf(&res, "[%s%d]>%s %s", cstr, todo->id, todo->note,
110 todo->mesg);
111 else
112 asprintf(&res, "[%s%d] %s", cstr, todo->id, todo->mesg);
113
114 return res;
115 }
116
todo_hash(struct todo * todo)117 char *todo_hash(struct todo *todo)
118 {
119 char *raw = todo_tostr(todo);
120 char *sha1 = mem_malloc(SHA1_DIGESTLEN * 2 + 1);
121 sha1_digest(raw, sha1);
122 mem_free(raw);
123
124 return sha1;
125 }
126
todo_write(struct todo * todo,FILE * f)127 void todo_write(struct todo *todo, FILE * f)
128 {
129 char *str = todo_tostr(todo);
130 fprintf(f, "%s\n", str);
131 mem_free(str);
132 }
133
134 /* Delete a note previously attached to a todo item. */
todo_delete_note(struct todo * todo)135 void todo_delete_note(struct todo *todo)
136 {
137 if (!todo->note)
138 EXIT(_("no note attached"));
139 erase_note(&todo->note);
140 }
141
142 /* Delete an item from the todo linked list. */
todo_delete(struct todo * todo)143 void todo_delete(struct todo *todo)
144 {
145 llist_item_t *i = LLIST_FIND_FIRST(&todolist, todo, NULL);
146
147 if (!i)
148 EXIT(_("no such todo"));
149
150 LLIST_REMOVE(&todolist, i);
151 mem_free(todo->mesg);
152 erase_note(&todo->note);
153 mem_free(todo);
154 }
155
156 /*
157 * Make sure an item is located at the right position within the sorted list.
158 */
todo_resort(struct todo * t)159 void todo_resort(struct todo *t)
160 {
161 LLIST_REORDER(&todolist, t, todo_cmp);
162 }
163
164 /* Flag a todo item. */
todo_flag(struct todo * t)165 void todo_flag(struct todo *t)
166 {
167 t->completed = !t->completed;
168 todo_resort(t);
169 }
170
171 /*
172 * Returns the position into the linked list corresponding to the
173 * given todo item.
174 */
todo_get_position(struct todo * needle,int skip_completed)175 int todo_get_position(struct todo *needle, int skip_completed)
176 {
177 llist_item_t *i;
178 int n = 0;
179
180 if (skip_completed) {
181 LLIST_FIND_FOREACH(&todolist, NULL, todo_is_uncompleted, i) {
182 if (LLIST_TS_GET_DATA(i) == needle)
183 return n;
184 n++;
185 }
186 } else {
187 LLIST_FOREACH(&todolist, i) {
188 if (LLIST_TS_GET_DATA(i) == needle)
189 return n;
190 n++;
191 }
192 }
193
194 return -1;
195 }
196
197 /* Attach a note to a todo */
todo_edit_note(struct todo * i,const char * editor)198 void todo_edit_note(struct todo *i, const char *editor)
199 {
200 edit_note(&i->note, editor);
201 }
202
203 /* View a note previously attached to a todo */
todo_view_note(struct todo * i,const char * pager)204 void todo_view_note(struct todo *i, const char *pager)
205 {
206 view_note(i->note, pager);
207 }
208
todo_free(struct todo * todo)209 void todo_free(struct todo *todo)
210 {
211 mem_free(todo->mesg);
212 erase_note(&todo->note);
213 mem_free(todo);
214 }
215
todo_init_list(void)216 void todo_init_list(void)
217 {
218 LLIST_INIT(&todolist);
219 }
220
todo_free_list(void)221 void todo_free_list(void)
222 {
223 LLIST_FREE_INNER(&todolist, todo_free);
224 LLIST_FREE(&todolist);
225 }
226