1 /*
2  * Copyright (c) 2011-2014 LEVAI Daniel
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *	* Redistributions of source code must retain the above copyright
8  *	notice, this list of conditions and the following disclaimer.
9  *	* Redistributions in binary form must reproduce the above copyright
10  *	notice, this list of conditions and the following disclaimer in the
11  *	documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24 
25 
26 #include "common.h"
27 #include "commands.h"
28 
29 
30 char	swap_keys(xmlNodePtr *, xmlNodePtr *);
31 
32 
33 extern db_parameters	db_params;
34 extern xmlNodePtr	keychain;
35 
36 
37 void
cmd_swap(const char * e_line,command * commands)38 cmd_swap(const char *e_line, command *commands)
39 {
40 	xmlNodePtr	key_src = NULL, key_dst = NULL, key_finish = NULL;
41 
42 	char			*modified = NULL;
43 	char			insert = 0;
44 	char			*line = NULL, *cmd = NULL, *inv = NULL;
45 	unsigned long int	idx_src = 0, idx_dst = 0;
46 
47 
48 	line = strdup(e_line); malloc_check(line);
49 
50 
51 	cmd = strtok(line, " ");	/* command name */
52 	if (!cmd) {
53 		puts(commands->usage);
54 
55 		free(line); line = NULL;
56 		return;
57 	}
58 
59 	if (strcmp(cmd, "insert") == 0)
60 		insert = 1;
61 
62 
63 	cmd = strtok(NULL, " ");	/* first parameter, the source index number */
64 	if (!cmd) {
65 		puts(commands->usage);
66 
67 		free(line); line = NULL;
68 		return;
69 	}
70 
71 	errno = 0;
72 	idx_src = strtoul((const char *)cmd, &inv, 10);
73 	if (inv[0] != '\0'  ||  errno != 0  ||  cmd[0] == '-') {
74 		puts(commands->usage);
75 
76 		free(line); line = NULL;
77 		return;
78 	}
79 
80 
81 	cmd = strtok(NULL, " ");	/* second parameter, the destination index number */
82 	if (!cmd) {
83 		puts(commands->usage);
84 
85 		free(line); line = NULL;
86 		return;
87 	}
88 
89 	errno = 0;
90 	idx_dst = strtoul((const char *)cmd, &inv, 10);
91 	if (inv[0] != '\0'  ||  errno != 0  ||  cmd[0] == '-') {
92 		puts(commands->usage);
93 
94 		free(line); line = NULL;
95 		return;
96 	}
97 
98 
99 	free(line); line = NULL;
100 
101 
102 	/* No funny stuff!!! :) */
103 	if (idx_src == idx_dst) {
104 		puts("The two indices are the same!");
105 		return;
106 	}
107 
108 	key_src = find_key(idx_src);
109 	if (!key_src) {
110 		puts("Invalid source index!");
111 		return;
112 	}
113 	key_dst = find_key(idx_dst);
114 	if (!key_dst) {
115 		puts("Invalid destination index!");
116 		return;
117 	}
118 
119 
120 	if (!swap_keys(&key_src, &key_dst)) {
121 		if (insert)
122 			puts("Error while preparing to insert key!");
123 		else
124 			puts("Error while trying to swap keys!");
125 
126 		return;
127 	}
128 
129 
130 	if (insert) {
131 		/* Inserting is basically swapping the two indices, then shift the surrounding indices ...
132 		 *
133 		 * if (idx_src > idx_dst)
134 		 * ... from the bottom to the top
135 		 *
136 		 * if (idx_src < idx_dst)
137 		 * ... from the top to the bottom
138 		 */
139 
140 		key_finish = key_src;
141 		key_src = key_dst;
142 
143 		/* We skip one node; it's the text node for formatting */
144 		if (idx_src > idx_dst)
145 			key_dst = key_src->prev->prev;
146 		else
147 			key_dst = key_src->next->next;
148 
149 		while (key_dst) {
150 			/* finish */
151 			if (key_dst == key_finish)
152 				break;
153 
154 			if (key_dst->type != XML_ELEMENT_NODE) {
155 				puts("Error while trying to insert key! Please check your key list and reload your database without saving, if necessary!");
156 				if (getenv("KC_DEBUG"))
157 					puts("key_dst is non-element node!");
158 
159 				return;
160 			}
161 
162 			if (!swap_keys(&key_src, &key_dst)) {
163 				puts("Error while trying to insert key! Please check your key list and reload your database without saving, if necessary!");
164 				if (getenv("KC_DEBUG"))
165 					puts("swap_key() error while shifting nodes!");
166 
167 				return;
168 			}
169 
170 			if (idx_src > idx_dst)
171 				key_dst = key_src->prev->prev;
172 			else
173 				key_dst = key_src->next->next;
174 		}
175 	}
176 
177 	/* Update the current keychain's modified timestamp */
178 	modified = malloc(TIME_MAXLEN); malloc_check(modified);
179 	snprintf(modified, TIME_MAXLEN, "%d", (int)time(NULL));
180 
181 	xmlSetProp(keychain, BAD_CAST "modified", BAD_CAST modified);
182 
183 	free(modified); modified = NULL;
184 
185 	if (insert)
186 		printf("Key %lu was inserted at %lu\n", idx_src, idx_dst);
187 	else
188 		printf("Key %lu was swapped with %lu\n", idx_src, idx_dst);
189 
190 	puts("Key indices may have been changed. Make sure to 'list', before using them again!");
191 
192 	db_params.dirty = 1;
193 } /* cmd_swap() */
194 
195 
196 char
swap_keys(xmlNodePtr * key_src,xmlNodePtr * key_dst)197 swap_keys(xmlNodePtr *key_src, xmlNodePtr *key_dst)
198 {
199 	xmlNodePtr	key_tmp_src = NULL, key_tmp_dst = NULL;
200 
201 
202 	/* duplicate the source key */
203 	key_tmp_src = xmlCopyNode(*key_src, 2);
204 	if (!key_tmp_src) {
205 		puts("Error duplicating source entry!");
206 
207 		if (getenv("KC_DEBUG"))
208 			puts("xmlCopyNode() error!");
209 
210 		return(0);
211 	}
212 
213 	/* duplicate the destination key */
214 	key_tmp_dst = xmlCopyNode(*key_dst, 2);
215 	if (!key_tmp_dst) {
216 		puts("Error duplicating destination entry!");
217 
218 		if (getenv("KC_DEBUG"))
219 			puts("xmlCopyNode() error!");
220 
221 		return(0);
222 	}
223 
224 
225 	/* We need two key_tmp_* variables, because xmlReplaceNode() unlinks both its parameters */
226 	xmlReplaceNode(*key_src, key_tmp_dst);
227 	xmlFreeNode(*key_src);
228 
229 	xmlReplaceNode(*key_dst, key_tmp_src);
230 	xmlFreeNode(*key_dst);
231 
232 	*key_src = key_tmp_src;	/* the original "source" index */
233 	*key_dst = key_tmp_dst;	/* the original "destination" index */
234 
235 	return(1);
236 } /* swap_keys() */
237