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