1 /* Copyright (c) 2012, Bastien Dejean
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this
8  *    list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright notice,
10  *    this list of conditions and the following disclaimer in the documentation
11  *    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 OWNER OR CONTRIBUTORS BE LIABLE FOR
17  * ANY 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 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include "bspwm.h"
30 #include "desktop.h"
31 #include "ewmh.h"
32 #include "history.h"
33 #include "pointer.h"
34 #include "monitor.h"
35 #include "query.h"
36 #include "stack.h"
37 #include "tree.h"
38 #include "settings.h"
39 #include "subscribe.h"
40 #include "restore.h"
41 #include "window.h"
42 #include "parse.h"
43 
restore_state(const char * file_path)44 bool restore_state(const char *file_path)
45 {
46 	size_t jslen;
47 	char *json = read_string(file_path, &jslen);
48 
49 	if (json == NULL) {
50 		return false;
51 	}
52 
53 	int nbtok = 256;
54 	jsmn_parser parser;
55 	jsmntok_t *tokens = malloc(nbtok * sizeof(jsmntok_t));
56 
57 	if (tokens == NULL) {
58 		perror("Restore tree: malloc");
59 		free(json);
60 		return false;
61 	}
62 
63 	jsmn_init(&parser);
64 	int ret;
65 
66 	while ((ret = jsmn_parse(&parser, json, jslen, tokens, nbtok)) == JSMN_ERROR_NOMEM) {
67 		nbtok *= 2;
68 		jsmntok_t *rtokens = realloc(tokens, nbtok * sizeof(jsmntok_t));
69 		if (rtokens == NULL) {
70 			perror("Restore tree: realloc");
71 			free(tokens);
72 			free(json);
73 			return false;
74 		} else {
75 			tokens = rtokens;
76 		}
77 	}
78 
79 	if (ret < 0) {
80 		warn("Restore tree: jsmn_parse: ");
81 		switch (ret) {
82 			case JSMN_ERROR_NOMEM:
83 				warn("not enough memory.\n");
84 				break;
85 			case JSMN_ERROR_INVAL:
86 				warn("found invalid character inside JSON string.\n");
87 				break;
88 			case JSMN_ERROR_PART:
89 				warn("not a full JSON packet.\n");
90 				break;
91 			default:
92 				warn("unknown error.\n");
93 				break;
94 		}
95 
96 		free(tokens);
97 		free(json);
98 
99 		return false;
100 	}
101 
102 	int num = tokens[0].size;
103 
104 	if (num < 1) {
105 		free(tokens);
106 		free(json);
107 
108 		return false;
109 	}
110 
111 	mon = NULL;
112 	while (mon_head != NULL) {
113 		remove_monitor(mon_head);
114 	}
115 
116 	jsmntok_t *t = tokens + 1;
117 	uint32_t focused_monitor_id = 0, primary_monitor_id = 0;
118 	jsmntok_t *focus_history_token = NULL, *stacking_list_token = NULL;
119 
120 	for (int i = 0; i < num; i++) {
121 		if (keyeq("focusedMonitorId", t, json)) {
122 			t++;
123 			sscanf(json + t->start, "%u", &focused_monitor_id);
124 		} else if (keyeq("primaryMonitorId", t, json)) {
125 			t++;
126 			sscanf(json + t->start, "%u", &primary_monitor_id);
127 		} else if (keyeq("clientsCount", t, json)) {
128 			t++;
129 			sscanf(json + t->start, "%u", &clients_count);
130 		} else if (keyeq("monitors", t, json)) {
131 			t++;
132 			int s = t->size;
133 			t++;
134 			for (int j = 0; j < s; j++) {
135 				monitor_t *m = restore_monitor(&t, json);
136 				if (m->desk == NULL) {
137 					add_desktop(m, make_desktop(NULL, XCB_NONE));
138 				}
139 				add_monitor(m);
140 			}
141 			continue;
142 		} else if (keyeq("focusHistory", t, json)) {
143 			t++;
144 			if (mon == NULL) {
145 				focus_history_token = t;
146 			}
147 			restore_history(&t, json);
148 			continue;
149 		} else if (keyeq("stackingList", t, json)) {
150 			t++;
151 			if (mon == NULL) {
152 				stacking_list_token = t;
153 			}
154 			restore_stack(&t, json);
155 			continue;
156 		} else if (keyeq("eventSubscribers", t, json)) {
157 			t++;
158 			restore_subscribers(&t, json);
159 			continue;
160 		}
161 		t++;
162 	}
163 
164 	if (focused_monitor_id != 0) {
165 		coordinates_t loc;
166 		if (monitor_from_id(focused_monitor_id, &loc)) {
167 			mon = loc.monitor;
168 		}
169 	}
170 
171 	if (primary_monitor_id != 0) {
172 		coordinates_t loc;
173 		if (monitor_from_id(primary_monitor_id, &loc)) {
174 			pri_mon = loc.monitor;
175 		}
176 	}
177 
178 	if (focus_history_token != NULL) {
179 		restore_history(&focus_history_token, json);
180 	}
181 
182 	if (stacking_list_token != NULL) {
183 		restore_stack(&stacking_list_token, json);
184 	}
185 
186 	for (monitor_t *m = mon_head; m != NULL; m = m->next) {
187 		m->id = xcb_generate_id(dpy);
188 		for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
189 			d->id = xcb_generate_id(dpy);
190 			regenerate_ids_in(d->root);
191 			refresh_presel_feedbacks(m, d, d->root);
192 			restack_presel_feedbacks(d);
193 
194 			for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
195 				if (n->client == NULL) {
196 					continue;
197 				}
198 				initialize_client(n);
199 				uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)};
200 				xcb_change_window_attributes(dpy, n->id, XCB_CW_EVENT_MASK, values);
201 				window_grab_buttons(n->id);
202 			}
203 		}
204 	}
205 
206 	ewmh_update_number_of_desktops();
207 	ewmh_update_desktop_names();
208 	ewmh_update_desktop_viewport();
209 	ewmh_update_current_desktop();
210 	ewmh_update_client_list(false);
211 	ewmh_update_client_list(true);
212 	ewmh_update_active_window();
213 
214 	free(tokens);
215 	free(json);
216 
217 	return true;
218 }
219 
220 #define RESTORE_INT(k, p) \
221 	} else if (keyeq(#k, *t, json)) { \
222 		(*t)++; \
223 		sscanf(json + (*t)->start, "%i", p);
224 
225 #define RESTORE_UINT(k, p) \
226 	} else if (keyeq(#k, *t, json)) { \
227 		(*t)++; \
228 		sscanf(json + (*t)->start, "%u", p);
229 
230 #define RESTORE_USINT(k, p) \
231 	} else if (keyeq(#k, *t, json)) { \
232 		(*t)++; \
233 		sscanf(json + (*t)->start, "%hu", p);
234 
235 #define RESTORE_DOUBLE(k, p) \
236 	} else if (keyeq(#k, *t, json)) { \
237 		(*t)++; \
238 		sscanf(json + (*t)->start, "%lf", p);
239 
240 #define RESTORE_ANY(k, p, f) \
241 	} else if (keyeq(#k, *t, json)) { \
242 		(*t)++; \
243 		char *val = copy_string(json + (*t)->start, (*t)->end - (*t)->start); \
244 		f(val, p); \
245 		free(val);
246 
247 #define RESTORE_BOOL(k, p)  RESTORE_ANY(k, p, parse_bool)
248 
restore_monitor(jsmntok_t ** t,char * json)249 monitor_t *restore_monitor(jsmntok_t **t, char *json)
250 {
251 	int num = (*t)->size;
252 	(*t)++;
253 	monitor_t *m = make_monitor(NULL, NULL, UINT32_MAX);
254 	uint32_t focused_desktop_id = 0;
255 
256 	for (int i = 0; i < num; i++) {
257 		if (keyeq("name", *t, json)) {
258 			(*t)++;
259 			snprintf(m->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
260 		RESTORE_UINT(id, &m->id)
261 		RESTORE_UINT(randrId, &m->randr_id)
262 		RESTORE_BOOL(wired, &m->wired)
263 		RESTORE_UINT(stickyCount, &m->sticky_count)
264 		RESTORE_INT(windowGap, &m->window_gap)
265 		RESTORE_UINT(borderWidth, &m->border_width)
266 		RESTORE_UINT(focusedDesktopId, &focused_desktop_id)
267 		} else if (keyeq("padding", *t, json)) {
268 			(*t)++;
269 			restore_padding(&m->padding, t, json);
270 			continue;
271 		} else if (keyeq("rectangle", *t, json)) {
272 			(*t)++;
273 			restore_rectangle(&m->rectangle, t, json);
274 			update_root(m, &m->rectangle);
275 			continue;
276 		} else if (keyeq("desktops", *t, json)) {
277 			(*t)++;
278 			int s = (*t)->size;
279 			(*t)++;
280 			for (int j = 0; j < s; j++) {
281 				desktop_t *d = restore_desktop(t, json);
282 				add_desktop(m, d);
283 			}
284 			continue;
285 		} else {
286 			warn("Restore monitor: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
287 			(*t)++;
288 		}
289 		(*t)++;
290 	}
291 
292 	if (focused_desktop_id != 0) {
293 		for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
294 			if (d->id == focused_desktop_id) {
295 				m->desk = d;
296 				break;
297 			}
298 		}
299 	}
300 
301 	return m;
302 }
303 
restore_desktop(jsmntok_t ** t,char * json)304 desktop_t *restore_desktop(jsmntok_t **t, char *json)
305 {
306 	int s = (*t)->size;
307 	(*t)++;
308 	desktop_t *d = make_desktop(NULL, UINT32_MAX);
309 	xcb_window_t focusedNodeId = XCB_NONE;
310 
311 	for (int i = 0; i < s; i++) {
312 		if (keyeq("name", *t, json)) {
313 			(*t)++;
314 			snprintf(d->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
315 		RESTORE_UINT(id, &d->id)
316 		RESTORE_ANY(layout, &d->layout, parse_layout)
317 		RESTORE_ANY(userLayout, &d->user_layout, parse_layout)
318 		RESTORE_INT(windowGap, &d->window_gap)
319 		RESTORE_UINT(borderWidth, &d->border_width)
320 		} else if (keyeq("focusedNodeId", *t, json)) {
321 			(*t)++;
322 			sscanf(json + (*t)->start, "%u", &focusedNodeId);
323 		} else if (keyeq("padding", *t, json)) {
324 			(*t)++;
325 			restore_padding(&d->padding, t, json);
326 			continue;
327 		} else if (keyeq("root", *t, json)) {
328 			(*t)++;
329 			d->root = restore_node(t, json);
330 			continue;
331 		} else {
332 			warn("Restore desktop: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
333 			(*t)++;
334 		}
335 		(*t)++;
336 	}
337 
338 	if (focusedNodeId != XCB_NONE) {
339 		d->focus = find_by_id_in(d->root, focusedNodeId);
340 	}
341 
342 	return d;
343 }
344 
restore_node(jsmntok_t ** t,char * json)345 node_t *restore_node(jsmntok_t **t, char *json)
346 {
347 	if ((*t)->type == JSMN_PRIMITIVE) {
348 		(*t)++;
349 		return NULL;
350 	} else {
351 		int s = (*t)->size;
352 		(*t)++;
353 		/* hack to prevent a new ID from being generated */
354 		node_t *n = make_node(UINT32_MAX);
355 
356 		for (int i = 0; i < s; i++) {
357 			if (keyeq("id", *t, json)) {
358 				(*t)++;
359 				sscanf(json + (*t)->start, "%u", &n->id);
360 			RESTORE_ANY(splitType, &n->split_type, parse_split_type)
361 			RESTORE_DOUBLE(splitRatio, &n->split_ratio)
362 			RESTORE_BOOL(vacant, &n->vacant)
363 			RESTORE_BOOL(hidden, &n->hidden)
364 			RESTORE_BOOL(sticky, &n->sticky)
365 			RESTORE_BOOL(private, &n->private)
366 			RESTORE_BOOL(locked, &n->locked)
367 			RESTORE_BOOL(marked, &n->marked)
368 			} else if (keyeq("presel", *t, json)) {
369 				(*t)++;
370 				n->presel = restore_presel(t, json);
371 				continue;
372 			} else if (keyeq("rectangle", *t, json)) {
373 				(*t)++;
374 				restore_rectangle(&n->rectangle, t, json);
375 				continue;
376 			} else if (keyeq("constraints", *t, json)) {
377 				(*t)++;
378 				restore_constraints(&n->constraints, t, json);
379 				continue;
380 			} else if (keyeq("firstChild", *t, json)) {
381 				(*t)++;
382 				node_t *fc = restore_node(t, json);
383 				n->first_child = fc;
384 				if (fc != NULL) {
385 					fc->parent = n;
386 				}
387 				continue;
388 			} else if (keyeq("secondChild", *t, json)) {
389 				(*t)++;
390 				node_t *sc = restore_node(t, json);
391 				n->second_child = sc;
392 				if (sc != NULL) {
393 					sc->parent = n;
394 				}
395 				continue;
396 			} else if (keyeq("client", *t, json)) {
397 				(*t)++;
398 				n->client = restore_client(t, json);
399 				continue;
400 			} else {
401 				warn("Restore node: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
402 				(*t)++;
403 			}
404 			(*t)++;
405 		}
406 
407 		return n;
408 	}
409 }
410 
restore_presel(jsmntok_t ** t,char * json)411 presel_t *restore_presel(jsmntok_t **t, char *json)
412 {
413 	if ((*t)->type == JSMN_PRIMITIVE) {
414 		(*t)++;
415 		return NULL;
416 	} else {
417 		int s = (*t)->size;
418 		(*t)++;
419 		presel_t *p = make_presel();
420 
421 		for (int i = 0; i < s; i++) {
422 			if (keyeq("splitRatio", *t, json)) {
423 				(*t)++;
424 				sscanf(json + (*t)->start, "%lf", &p->split_ratio);
425 			RESTORE_ANY(splitDir, &p->split_dir, parse_direction)
426 			}
427 
428 			(*t)++;
429 		}
430 
431 		return p;
432 	}
433 }
434 
435 
restore_client(jsmntok_t ** t,char * json)436 client_t *restore_client(jsmntok_t **t, char *json)
437 {
438 	if ((*t)->type == JSMN_PRIMITIVE) {
439 		(*t)++;
440 		return NULL;
441 	} else {
442 		int s = (*t)->size;
443 		(*t)++;
444 		client_t *c = make_client();
445 
446 		for (int i = 0; i < s; i++) {
447 			if (keyeq("className", *t, json)) {
448 				(*t)++;
449 				snprintf(c->class_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
450 			} else if (keyeq("instanceName", *t, json)) {
451 				(*t)++;
452 				snprintf(c->instance_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
453 			RESTORE_ANY(state, &c->state, parse_client_state)
454 			RESTORE_ANY(lastState, &c->last_state, parse_client_state)
455 			RESTORE_ANY(layer, &c->layer, parse_stack_layer)
456 			RESTORE_ANY(lastLayer, &c->last_layer, parse_stack_layer)
457 			RESTORE_UINT(borderWidth, &c->border_width)
458 			RESTORE_BOOL(urgent, &c->urgent)
459 			RESTORE_BOOL(shown, &c->shown)
460 			} else if (keyeq("tiledRectangle", *t, json)) {
461 				(*t)++;
462 				restore_rectangle(&c->tiled_rectangle, t, json);
463 				continue;
464 			} else if (keyeq("floatingRectangle", *t, json)) {
465 				(*t)++;
466 				restore_rectangle(&c->floating_rectangle, t, json);
467 				continue;
468 			} else {
469 				warn("Restore client: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
470 				(*t)++;
471 			}
472 
473 			(*t)++;
474 		}
475 
476 		return c;
477 	}
478 }
479 
restore_rectangle(xcb_rectangle_t * r,jsmntok_t ** t,char * json)480 void restore_rectangle(xcb_rectangle_t *r, jsmntok_t **t, char *json)
481 {
482 	int s = (*t)->size;
483 	(*t)++;
484 
485 	for (int i = 0; i < s; i++) {
486 		if (keyeq("x", *t, json)) {
487 			(*t)++;
488 			sscanf(json + (*t)->start, "%hi", &r->x);
489 		} else if (keyeq("y", *t, json)) {
490 			(*t)++;
491 			sscanf(json + (*t)->start, "%hi", &r->y);
492 		} else if (keyeq("width", *t, json)) {
493 			(*t)++;
494 			sscanf(json + (*t)->start, "%hu", &r->width);
495 		} else if (keyeq("height", *t, json)) {
496 			(*t)++;
497 			sscanf(json + (*t)->start, "%hu", &r->height);
498 		}
499 		(*t)++;
500 	}
501 }
502 
restore_constraints(constraints_t * c,jsmntok_t ** t,char * json)503 void restore_constraints(constraints_t *c, jsmntok_t **t, char *json)
504 {
505 	int s = (*t)->size;
506 	(*t)++;
507 
508 	for (int i = 0; i < s; i++) {
509 		if (keyeq("min_width", *t, json)) {
510 			(*t)++;
511 			sscanf(json + (*t)->start, "%hu", &c->min_width);
512 		} else if (keyeq("min_height", *t, json)) {
513 			(*t)++;
514 			sscanf(json + (*t)->start, "%hu", &c->min_height);
515 		}
516 		(*t)++;
517 	}
518 }
519 
restore_padding(padding_t * p,jsmntok_t ** t,char * json)520 void restore_padding(padding_t *p, jsmntok_t **t, char *json)
521 {
522 	int s = (*t)->size;
523 	(*t)++;
524 
525 	for (int i = 0; i < s; i++) {
526 		if (keyeq("top", *t, json)) {
527 			(*t)++;
528 			sscanf(json + (*t)->start, "%i", &p->top);
529 		} else if (keyeq("right", *t, json)) {
530 			(*t)++;
531 			sscanf(json + (*t)->start, "%i", &p->right);
532 		} else if (keyeq("bottom", *t, json)) {
533 			(*t)++;
534 			sscanf(json + (*t)->start, "%i", &p->bottom);
535 		} else if (keyeq("left", *t, json)) {
536 			(*t)++;
537 			sscanf(json + (*t)->start, "%i", &p->left);
538 		}
539 		(*t)++;
540 	}
541 }
542 
restore_history(jsmntok_t ** t,char * json)543 void restore_history(jsmntok_t **t, char *json)
544 {
545 	int s = (*t)->size;
546 	(*t)++;
547 
548 	for (int i = 0; i < s; i++) {
549 		coordinates_t loc = {NULL, NULL, NULL};
550 		restore_coordinates(&loc, t, json);
551 		if (loc.monitor != NULL && loc.desktop != NULL) {
552 			history_add(loc.monitor, loc.desktop, loc.node, true);
553 		}
554 	}
555 }
556 
restore_subscribers(jsmntok_t ** t,char * json)557 void restore_subscribers(jsmntok_t **t, char *json)
558 {
559 	int s = (*t)->size;
560 	(*t)++;
561 
562 	for (int i = 0; i < s; i++) {
563 		subscriber_list_t *s = make_subscriber(NULL, NULL, 0, 0);
564 		restore_subscriber(s, t, json);
565 		add_subscriber(s);
566 	}
567 }
568 
restore_subscriber(subscriber_list_t * s,jsmntok_t ** t,char * json)569 void restore_subscriber(subscriber_list_t *s, jsmntok_t **t, char *json)
570 {
571 	int n = (*t)->size;
572 	(*t)++;
573 
574 	for (int i = 0; i < n; i++) {
575 		if (keyeq("fileDescriptor", *t, json)) {
576 			(*t)++;
577 			int fd;
578 			sscanf(json + (*t)->start, "%i", &fd);
579 			s->stream = fdopen(fd, "w");
580 		} else if (keyeq("fifoPath", *t, json)) {
581 			(*t)++;
582 			free(s->fifo_path);
583 			s->fifo_path = copy_string(json + (*t)->start, (*t)->end - (*t)->start);
584 		RESTORE_INT(field, &s->field)
585 		RESTORE_INT(count, &s->count)
586 		}
587 		(*t)++;
588 	}
589 }
590 
restore_coordinates(coordinates_t * loc,jsmntok_t ** t,char * json)591 void restore_coordinates(coordinates_t *loc, jsmntok_t **t, char *json)
592 {
593 	int s = (*t)->size;
594 	(*t)++;
595 	uint32_t id = 0;
596 
597 	for (int i = 0; i < s; i++) {
598 		if (keyeq("monitorId", *t, json)) {
599 			(*t)++;
600 			sscanf(json + (*t)->start, "%u", &id);
601 			loc->monitor = find_monitor(id);
602 		} else if (keyeq("desktopId", *t, json)) {
603 			(*t)++;
604 			sscanf(json + (*t)->start, "%u", &id);
605 			loc->desktop = find_desktop_in(id, loc->monitor);
606 		} else if (keyeq("nodeId", *t, json)) {
607 			(*t)++;
608 			sscanf(json + (*t)->start, "%u", &id);
609 			loc->node = find_by_id_in(loc->desktop != NULL ? loc->desktop->root : NULL, id);
610 		}
611 		(*t)++;
612 	}
613 }
614 
restore_stack(jsmntok_t ** t,char * json)615 void restore_stack(jsmntok_t **t, char *json)
616 {
617 	int s = (*t)->size;
618 	(*t)++;
619 
620 	for (int i = 0; i < s; i++) {
621 		uint32_t id;
622 		sscanf(json + (*t)->start, "%u", &id);
623 		coordinates_t loc;
624 		if (locate_window(id, &loc)) {
625 			stack_insert_after(stack_tail, loc.node);
626 		}
627 		(*t)++;
628 	}
629 }
630 
631 #undef RESTORE_INT
632 #undef RESTORE_UINT
633 #undef RESTORE_USINT
634 #undef RESTORE_DOUBLE
635 #undef RESTORE_ANY
636 #undef RESTORE_BOOL
637 
keyeq(char * s,jsmntok_t * key,char * json)638 bool keyeq(char *s, jsmntok_t *key, char *json)
639 {
640 	size_t n = key->end - key->start;
641 	return (strlen(s) == n && strncmp(s, json + key->start, n) == 0);
642 }
643