]> cygwin.com Git - cygwin-apps/setup.git/blob - choose.cc
2001-11-29 Robert Collins <rbtcollins@hotmail.com>
[cygwin-apps/setup.git] / choose.cc
1 /*
2 * Copyright (c) 2000, 2001 Red Hat, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by DJ Delorie <dj@cygnus.com>
13 *
14 */
15
16 /* The purpose of this file is to let the user choose which packages
17 to install, and which versions of the package when more than one
18 version is provided. The "trust" level serves as an indication as
19 to which version should be the default choice. At the moment, all
20 we do is compare with previously installed packages to skip any
21 that are already installed (by setting the action to ACTION_SAME).
22 While the "trust" stuff is supported, it's not really implemented
23 yet. We always prefer the "current" option. In the future, this
24 file might have a user dialog added to let the user choose to not
25 install packages, or to install packages that aren't installed by
26 default. */
27
28 #if 0
29 static const char *cvsid =
30 "\n%%% $Id$\n";
31 #endif
32
33 #include "win32.h"
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <io.h>
37 #include <ctype.h>
38
39 #include "dialog.h"
40 #include "resource.h"
41 #include "state.h"
42 #include "ini.h"
43 #include "concat.h"
44 #include "msg.h"
45 #include "log.h"
46 #include "find.h"
47 #include "filemanip.h"
48 #include "io_stream.h"
49 #include "choose.h"
50 #include "category.h"
51 #include "category_list.h"
52
53 #include "package_db.h"
54 #include "package_meta.h"
55 #include "package_version.h"
56
57 #include "port.h"
58
59 #define alloca __builtin_alloca
60
61 #define HMARGIN 10
62 #define ROW_MARGIN 5
63 #define ICON_MARGIN 4
64 #define NEW_COL_SIZE_SLOP (ICON_MARGIN + 11)
65
66 #define CHECK_SIZE 11
67
68 static int initialized = 0;
69
70 static int scroll_ulc_x, scroll_ulc_y;
71
72 static HWND lv, nextbutton, choose_inst_text;
73 static TEXTMETRIC tm;
74 static int header_height;
75 static HANDLE sysfont;
76 static int row_height;
77 static HANDLE bm_spin, bm_rtarrow, bm_checkyes, bm_checkno, bm_checkna;
78 static HDC bitmap_dc;
79 static view *chooser = NULL;
80 static trusts deftrust = TRUST_UNKNOWN;
81
82 static struct _header pkg_headers[] = {
83 {"Current", 7, 0, 0},
84 {"New", 3, 0, 0},
85 {"Src?", 4, 0, 0},
86 {"Category", 8, 0, 0},
87 {"Package", 7, 0, 0},
88 {0, 0, 0, 0}
89 };
90
91 static struct _header cat_headers[] = {
92 {"Category", 8, 0, 0},
93 {"Current", 7, 0, 0},
94 {"New", 3, 0, 0},
95 {"Src?", 4, 0, 0},
96 {"Package", 7, 0, 0},
97 {0, 0, 0, 0}
98 };
99
100 static int add_required (packagemeta & pkg, size_t depth=0);
101 static void set_view_mode (HWND h, views mode);
102
103 #define pkgtrustp(pkg,t) (packageversion *)(t==TRUST_PREV ? pkg->prev : t == TRUST_CURR ? pkg->curr : pkg->exp)
104
105 /* Set the next action given a current action. */
106 static void
107 set_action (packagemeta * pkg)
108 {
109 /* actions are the following:
110
111 for install modes (from net/local)
112 for each version:
113 install this version
114 install the source for this version
115 and a boolean flag - force install to allow reinstallation, or bypassing requirements
116 globally:
117 install the source for the current version.
118
119 to uninstall a package, the desired version is set to NULL;
120
121 for mirroring modes (download only)
122 for each version
123 download this version
124 download source for this version
125
126 these are represented by the following:
127 the desired pointer in the packagemetadata indicated which version we are operating on.
128 if we are operating on the installed version, reinstall is a valid option.
129 for the selected version, forceinstall means Do an install no matter what, and
130 srcpicked means download the source.
131
132 The default action for any installed package is to install the 'curr version'
133 if it is not already installed.
134
135 The default action for any non-installed package is to do nothing.
136
137 To achieve a no-op, set desired==installed, and if (installed) set forceinstall=0 and
138 srcpicked = 0;
139
140 Iteration through versions should follow the following rules:
141 selected radio button (prev/curr/test) (show as reinstall if that is the
142 current version) ->source only (only if the package is installed) ->oldest version....skip version of radio button...
143 newest version->uninstall->no-op->selected radio button.
144
145 If any state cannot be set (ie because (say) no prev entry exists for a package
146 simply progress to the next option.
147
148 */
149
150 /* We were set to uninstall the package */
151 if (!pkg->desired && pkg->installed)
152 {
153 /* No-op - keep whatever we've got */
154 pkg->desired = pkg->installed;
155 if (pkg->desired)
156 {
157 pkg->desired->binpicked = 0;
158 pkg->desired->srcpicked = 0;
159 }
160 return;
161 }
162 else if (pkg->desired == pkg->installed
163 && (!pkg->installed
164 || !(pkg->installed->binpicked || pkg->installed->srcpicked)))
165 /* Install the default trust version - this is a 'reinstall' for installed
166 * packages */
167 {
168 pkg->desired = NULL;
169 /* No-op */
170 pkg->desired = pkgtrustp (pkg, deftrust);
171 if (pkg->desired)
172 {
173 pkg->desired->binpicked = 1;
174 return;
175 }
176 }
177 /* are we currently on the radio button selection and installed */
178 if (pkg->desired == pkgtrustp (pkg, deftrust) && pkg->installed &&
179 (!pkg->desired || pkg->desired->binpicked))
180 {
181 /* FIXME: is source available */
182 /* source only this file */
183 pkg->desired = pkg->installed;
184 pkg->desired->binpicked = 0;
185 pkg->desired->srcpicked = 1;
186 return;
187 }
188 /* are we currently on source only or on the radio button but not installed */
189 else if ((pkg->desired == pkg->installed && pkg->installed
190 && pkg->installed->srcpicked) ||
191 pkg->desired == pkgtrustp (pkg, deftrust))
192 {
193 /* move onto the loop through versions */
194 pkg->desired = pkg->versions.getnth (1);
195 if (pkg->desired == pkgtrustp (pkg, deftrust))
196 pkg->desired =
197 pkg->versions.number () > 1 ? pkg->versions.getnth (2) : NULL;
198 if (pkg->desired)
199 {
200 pkg->desired->binpicked = 1;
201 pkg->desired->srcpicked = 0;
202 }
203 return;
204 }
205 else
206 {
207 /* preserve the src tick box */
208 int source = pkg->desired->srcpicked;
209 /* bump the version selected, skipping the radio button trust along the way */
210 size_t n;
211 for (n = 1;
212 n <= pkg->versions.number ()
213 && pkg->desired != pkg->versions.getnth (n); n++);
214 /* n points at pkg->desired */
215 n++;
216 if (n <= pkg->versions.number ())
217 {
218 if (pkgtrustp (pkg, deftrust) == pkg->versions.getnth (n))
219 n++;
220 if (n <= pkg->versions.number ())
221 {
222 pkg->desired = pkg->versions.getnth (n);
223 pkg->desired->srcpicked = source;
224 return;
225 }
226 }
227 /* went past the end - uninstall the package */
228 pkg->desired = NULL;
229 }
230 }
231
232 static int
233 add_required (packagemeta & pkg, size_t depth = 0)
234 {
235 Dependency *dp;
236 packagemeta *required;
237 int changed = 0;
238 if (!pkg.desired
239 || (pkg.desired != pkg.installed && !pkg.desired->binpicked))
240 /* uninstall || source only */
241 return 0;
242
243 dp = pkg.desired->required;
244 packagedb db;
245 /* cheap test for too much recursion */
246 if (depth > db.npackages ())
247 return 0;
248 while (dp)
249 {
250 if ((required = db.getpackagebyname (dp->package)) == NULL)
251 {
252 dp = dp->next;
253 changed++;
254 continue;
255 }
256 if (!required->desired)
257 {
258 /* it's set to uninstall */
259 set_action (required);
260 }
261 else if (required->desired != required->installed
262 && !required->desired->binpicked)
263 {
264 /* it's set to change to a different version source only */
265 required->desired->binpicked = 1;
266 }
267 /* does this requirement have requirements? */
268 changed += add_required (*required, depth + 1);
269 dp = dp->next;
270 }
271 return changed;
272 }
273
274 /* Return an appropriate caption given the current action. */
275 char const *
276 choose_caption (packagemeta * pkg)
277 {
278 if (!pkg->desired && pkg->installed)
279 return "Uninstall";
280 else if (!pkg->desired)
281 return "Skip";
282 else if (pkg->desired == pkg->installed && pkg->desired->binpicked)
283 return source == IDC_SOURCE_DOWNLOAD ? "Retrieve" : "Reinstall";
284 else if (pkg->desired == pkg->installed && pkg->desired->srcpicked)
285 /* FIXME: Redo source should come up if the tarball is already present locally */
286 return "Source";
287 else if (pkg->desired == pkg->installed) /* and neither src nor bin */
288 return "Keep";
289 else
290 return pkg->desired->Canonical_version ();
291 }
292
293 static void
294 paint (HWND hwnd)
295 {
296 HDC hdc;
297 PAINTSTRUCT ps;
298 int x, y, i, ii;
299
300 hdc = BeginPaint (hwnd, &ps);
301
302 SelectObject (hdc, sysfont);
303 SetBkColor (hdc, GetSysColor (COLOR_WINDOW));
304 SetTextColor (hdc, GetSysColor (COLOR_WINDOWTEXT));
305
306 RECT cr;
307 GetClientRect (hwnd, &cr);
308
309 POINT p;
310
311 x = cr.left - scroll_ulc_x;
312 y = cr.top - scroll_ulc_y + header_height;
313
314
315 for (i = 0; i <= chooser->last_col; i++)
316 {
317 TextOut (hdc, x + chooser->headers[i].x, 3, chooser->headers[i].text,
318 chooser->headers[i].slen);
319 MoveToEx (hdc, x + chooser->headers[i].x, header_height - 3, &p);
320 LineTo (hdc, x + chooser->headers[i].x + chooser->headers[i].width,
321 header_height - 3);
322 }
323
324 IntersectClipRect (hdc, cr.left, cr.top + header_height, cr.right,
325 cr.bottom);
326
327 for (ii = 0; ii < chooser->nlines; ii++)
328 chooser->lines[ii].paint (hdc, x, y, ii,
329 (chooser->get_view_mode () ==
330 VIEW_CATEGORY) ? 0 : 1);
331
332 if (chooser->nlines == 0)
333 {
334 static const char *msg = "Nothing to Install/Update";
335 if (source == IDC_SOURCE_DOWNLOAD)
336 msg = "Nothing to Download";
337 TextOut (hdc, HMARGIN, header_height, msg, strlen (msg));
338 }
339
340 EndPaint (hwnd, &ps);
341 }
342
343 static void
344 scroll_common (HWND hwnd, int which, int *var, int code)
345 {
346 SCROLLINFO si;
347 si.cbSize = sizeof (si);
348 si.fMask = SIF_ALL;
349 GetScrollInfo (hwnd, which, &si);
350
351 switch (code)
352 {
353 case SB_THUMBTRACK:
354 si.nPos = si.nTrackPos;
355 break;
356 case SB_THUMBPOSITION:
357 break;
358 case SB_BOTTOM:
359 si.nPos = si.nMax;
360 break;
361 case SB_TOP:
362 si.nPos = 0;
363 break;
364 case SB_LINEDOWN:
365 si.nPos += row_height;
366 break;
367 case SB_LINEUP:
368 si.nPos -= row_height;
369 break;
370 case SB_PAGEDOWN:
371 si.nPos += si.nPage * 9 / 10;
372 break;
373 case SB_PAGEUP:
374 si.nPos -= si.nPage * 9 / 10;
375 break;
376 }
377
378 if ((int) si.nPos < 0)
379 si.nPos = 0;
380 if (si.nPos + si.nPage > (unsigned int) si.nMax)
381 si.nPos = si.nMax - si.nPage;
382
383 si.fMask = SIF_POS;
384 SetScrollInfo (hwnd, which, &si, TRUE);
385
386 int ox = scroll_ulc_x;
387 int oy = scroll_ulc_y;
388 *var = si.nPos;
389
390 RECT cr, sr;
391 GetClientRect (hwnd, &cr);
392 sr = cr;
393 sr.top += header_height;
394 ScrollWindow (hwnd, ox - scroll_ulc_x, oy - scroll_ulc_y, &sr, &sr);
395 sr.bottom = sr.top;
396 sr.top = cr.top;
397 ScrollWindow (hwnd, ox - scroll_ulc_x, 0, &sr, &sr);
398 }
399
400 static LRESULT CALLBACK
401 list_vscroll (HWND hwnd, HWND hctl, UINT code, int pos)
402 {
403 scroll_common (hwnd, SB_VERT, &scroll_ulc_y, code);
404 return 0;
405 }
406
407 static LRESULT CALLBACK
408 list_hscroll (HWND hwnd, HWND hctl, UINT code, int pos)
409 {
410 scroll_common (hwnd, SB_HORZ, &scroll_ulc_x, code);
411 return 0;
412 }
413
414 static LRESULT CALLBACK
415 list_click (HWND hwnd, BOOL dblclk, int x, int y, UINT hitCode)
416 {
417 int row, refresh;
418
419 if (chooser->nlines == 0)
420 return 0;
421
422 if (y < header_height)
423 return 0;
424 x += scroll_ulc_x;
425 y += scroll_ulc_y - header_height;
426
427 row = (y + ROW_MARGIN / 2) / row_height;
428
429 if (row < 0 || row >= chooser->nlines)
430 return 0;
431
432 refresh = chooser->click (row, x);
433
434 if (refresh)
435 {
436 RECT r;
437 GetClientRect (lv, &r);
438 SCROLLINFO si;
439 memset (&si, 0, sizeof (si));
440 si.cbSize = sizeof (si);
441 si.fMask = SIF_ALL; /* SIF_RANGE was giving strange behaviour */
442 si.nMin = 0;
443
444 si.nMax = chooser->nlines * row_height;
445 si.nPage = r.bottom - header_height;
446
447 /* if we are under the minimum display count ,
448 * set the offset to 0
449 */
450 if ((unsigned int) si.nMax <= si.nPage)
451 scroll_ulc_y = 0;
452 si.nPos = scroll_ulc_y;
453
454 SetScrollInfo (lv, SB_VERT, &si, TRUE);
455
456 InvalidateRect (lv, &r, TRUE);
457
458 }
459 else
460 {
461 RECT rect;
462 rect.left = chooser->headers[chooser->new_col].x - scroll_ulc_x;
463 rect.right = chooser->headers[chooser->src_col + 1].x - scroll_ulc_x;
464 rect.top = header_height + row * row_height - scroll_ulc_y;
465 rect.bottom = rect.top + row_height;
466 InvalidateRect (hwnd, &rect, TRUE);
467 }
468 return 0;
469 }
470
471 static LRESULT CALLBACK
472 listview_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
473 {
474 switch (message)
475 {
476 case WM_HSCROLL:
477 return HANDLE_WM_HSCROLL (hwnd, wParam, lParam, list_hscroll);
478 case WM_VSCROLL:
479 return HANDLE_WM_VSCROLL (hwnd, wParam, lParam, list_vscroll);
480 case WM_LBUTTONDOWN:
481 return HANDLE_WM_LBUTTONDOWN (hwnd, wParam, lParam, list_click);
482 case WM_PAINT:
483 paint (hwnd);
484 return 0;
485 default:
486 return DefWindowProc (hwnd, message, wParam, lParam);
487 }
488 }
489
490 static void
491 register_windows (HINSTANCE hinst)
492 {
493 WNDCLASSEX wcex;
494 static int done = 0;
495
496 if (done)
497 return;
498 done = 1;
499
500 memset (&wcex, 0, sizeof (wcex));
501 wcex.cbSize = sizeof (WNDCLASSEX);
502 wcex.style = CS_HREDRAW | CS_VREDRAW;
503 wcex.lpfnWndProc = listview_proc;
504 wcex.hInstance = hinst;
505 wcex.hIcon = LoadIcon (0, IDI_APPLICATION);
506 wcex.hCursor = LoadCursor (0, IDC_ARROW);
507 wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
508 wcex.lpszClassName = "listview";
509
510 RegisterClassEx (&wcex);
511 }
512
513 static void
514 note_width (struct _header *hdrs, HDC dc, const char *string, int addend,
515 int column)
516 {
517 if (!string)
518 return;
519 SIZE s;
520 GetTextExtentPoint32 (dc, string, strlen (string), &s);
521 if (hdrs[column].width < s.cx + addend)
522 hdrs[column].width = s.cx + addend;
523 }
524
525 static void
526 set_existence ()
527 {
528 /* FIXME:
529 iterate through the package list, and delete packages that are
530 * Not installed
531 * have no mirror site
532 and then do the same for categories with no packages.
533 */
534 }
535
536 static void
537 fill_missing_category ()
538 {
539 packagedb db;
540 for (packagemeta * pkg = db.getfirstpackage (); pkg;
541 pkg = db.getnextpackage ())
542 if (!pkg->Categories ().categories ())
543 pkg->add_category (db.categories.register_category ("Misc"));
544 }
545
546 static void
547 default_trust (HWND h, trusts trust)
548 {
549 deftrust = trust;
550 packagedb db;
551 for (packagemeta * pkg = db.getfirstpackage (); pkg;
552 pkg = db.getnextpackage ())
553 {
554 if (pkg->installed || pkg->Categories ().getcategorybyname ("Base")
555 || pkg->Categories ().getcategorybyname ("Misc"))
556 {
557 pkg->desired = pkgtrustp (pkg, trust);
558 if (pkg->desired)
559 {
560 pkg->desired->binpicked =
561 pkg->desired == pkg->installed ? 0 : 1;
562 pkg->desired->srcpicked = 0;
563 }
564 }
565 else
566 pkg->desired = 0;
567 }
568 RECT r;
569 GetClientRect (h, &r);
570 InvalidateRect (h, &r, TRUE);
571 if (nextbutton)
572 SetFocus (nextbutton);
573 }
574
575 void
576 pick_line::set_line (packagemeta * _pkg)
577 {
578 pkg = _pkg;
579 cat = NULL;
580 }
581
582 void
583 pick_line::set_line (Category * _cat)
584 {
585 cat = _cat;
586 pkg = NULL;
587 }
588
589 void
590 pick_line::paint (HDC hdc, int x, int y, int row, int show_cat)
591 {
592 int r = y + row * row_height;
593 int by = r + tm.tmHeight - 11;
594 if (pkg)
595 {
596 if (pkg->installed)
597 {
598 TextOut (hdc, x + chooser->headers[chooser->current_col].x, r,
599 pkg->installed->Canonical_version (),
600 strlen (pkg->installed->Canonical_version ()));
601 SelectObject (bitmap_dc, bm_rtarrow);
602 BitBlt (hdc, x + chooser->headers[chooser->current_col].x
603 + chooser->headers[0].width + ICON_MARGIN / 2
604 + HMARGIN / 2, by, 11, 11, bitmap_dc, 0, 0, SRCCOPY);
605 }
606
607 const char *s = choose_caption (pkg);
608 TextOut (hdc, x + chooser->headers[chooser->new_col].x
609 + NEW_COL_SIZE_SLOP, r, s, strlen (s));
610 SelectObject (bitmap_dc, bm_spin);
611 BitBlt (hdc, x + chooser->headers[chooser->new_col].x, by, 11, 11,
612 bitmap_dc, 0, 0, SRCCOPY);
613
614 HANDLE check_bm;
615 if ( /* uninstall */ !pkg->desired ||
616 /* source only */ (!pkg->desired->binpicked
617 && pkg->desired->srcpicked) ||
618 /* when no source mirror available */
619 !pkg->desired->src.sites.number ())
620 check_bm = bm_checkna;
621 else if (pkg->desired->srcpicked)
622 check_bm = bm_checkyes;
623 else
624 check_bm = bm_checkno;
625
626 SelectObject (bitmap_dc, check_bm);
627 BitBlt (hdc, x + chooser->headers[chooser->src_col].x, by, 11, 11,
628 bitmap_dc, 0, 0, SRCCOPY);
629
630 /* shows "first" category - do we want to show any? */
631 if (pkg->Categories ().getfirstcategory () && show_cat)
632 TextOut (hdc, x + chooser->headers[chooser->cat_col].x, r,
633 pkg->Categories ().getfirstcategory ()->name,
634 strlen (pkg->Categories ().getfirstcategory ()->name));
635
636 if (!pkg->SDesc ())
637 s = pkg->name;
638 else
639 {
640 static char buf[512];
641 strcpy (buf, pkg->name);
642 strcat (buf, ": ");
643 strcat (buf, pkg->SDesc ());
644 s = buf;
645 }
646 TextOut (hdc, x + chooser->headers[chooser->pkg_col].x, r, s,
647 strlen (s));
648 }
649 else if (cat)
650 TextOut (hdc, x + chooser->headers[chooser->cat_col].x, r, cat->name,
651 strlen (cat->name));
652 }
653
654 int
655 pick_line::click (int x)
656 {
657 if (pkg)
658 {
659 if (pkg->desired && pkg->desired->src.sites.number ()
660 && x >= chooser->headers[chooser->src_col].x - HMARGIN / 2
661 && x <= chooser->headers[chooser->src_col + 1].x - HMARGIN / 2)
662 pkg->desired->srcpicked ^= 1;
663
664 if (x >= chooser->headers[chooser->new_col].x - (HMARGIN / 2)
665 && x <= chooser->headers[chooser->new_col + 1].x - HMARGIN / 2)
666 {
667 set_action (pkg);
668 /* Add any packages that are needed by this package */
669 return add_required (*pkg);
670 }
671 }
672 else if (cat)
673 {
674 /* handle the catalog being clicked ... does this belong up a level.. ? */
675 }
676
677 return 0;
678 }
679
680 _view::_view (views _mode, HDC dc)
681 {
682 lines = NULL;
683 nlines = 0;
684 view_mode = VIEW_PACKAGE;
685 set_headers ();
686 init_headers (dc);
687 view_mode = VIEW_CATEGORY;
688 set_headers ();
689 init_headers (dc);
690
691 view_mode = _mode;
692 set_headers ();
693 }
694
695 void
696 _view::set_view_mode (views _mode)
697 {
698 if (_mode == NVIEW)
699 view_mode = VIEW_PACKAGE_FULL;
700 else
701 view_mode = _mode;
702 set_headers ();
703 }
704
705 const char *
706 _view::mode_caption ()
707 {
708 switch (view_mode)
709 {
710 case VIEW_UNKNOWN:
711 return "";
712 case VIEW_PACKAGE_FULL:
713 return "Full";
714 case VIEW_PACKAGE:
715 return "Partial";
716 case VIEW_CATEGORY:
717 return "Category";
718 default:
719 return "";
720 }
721 }
722
723 void
724 _view::set_headers (void)
725 {
726 switch (view_mode)
727 {
728 case VIEW_UNKNOWN:
729 return;
730 case VIEW_PACKAGE_FULL:
731 case VIEW_PACKAGE:
732 headers = pkg_headers;
733 current_col = 0;
734 new_col = 1;
735 src_col = 2;
736 cat_col = 3;
737 pkg_col = 4;
738 last_col = 4;
739 break;
740 case VIEW_CATEGORY:
741 headers = cat_headers;
742 current_col = 1;
743 new_col = 2;
744 src_col = 3;
745 cat_col = 0;
746 pkg_col = 4;
747 last_col = 4;
748 default:
749 return;
750 }
751 }
752
753 void
754 _view::init_headers (HDC dc)
755 {
756 int i;
757
758 for (i = 0; headers[i].text; i++)
759 headers[i].width = 0;
760
761 for (i = 0; headers[i].text; i++)
762 note_width (headers, dc, headers[i].text, 0, i);
763 packagedb db;
764 for (packagemeta * pkg = db.getfirstpackage (); pkg;
765 pkg = db.getnextpackage ())
766 {
767 if (pkg->installed)
768 {
769 note_width (headers, dc, pkg->installed->Canonical_version (), 0,
770 current_col);
771 note_width (headers, dc, pkg->installed->Canonical_version (),
772 NEW_COL_SIZE_SLOP, new_col);
773 }
774 for (size_t n = 1; n <= pkg->versions.number (); n++)
775 note_width (headers, dc,
776 pkg->versions.getnth (n)->Canonical_version (),
777 NEW_COL_SIZE_SLOP, new_col);
778 for (Category * cat = db.categories.getfirstcategory (); cat;
779 cat = cat->next)
780 note_width (headers, dc, cat->name, 0, cat_col);
781 if (!pkg->SDesc ())
782 note_width (headers, dc, pkg->name, 0, pkg_col);
783 else
784 {
785 static char buf[512];
786 strcpy (buf, pkg->name);
787 strcat (buf, ": ");
788 strcat (buf, pkg->SDesc ());
789 note_width (headers, dc, buf, 0, pkg_col);
790 }
791 }
792 note_width (headers, dc, "keep", NEW_COL_SIZE_SLOP, new_col);
793 note_width (headers, dc, "uninstall", NEW_COL_SIZE_SLOP, new_col);
794
795 headers[0].x = HMARGIN / 2;
796 for (i = 1; i <= last_col; i++)
797 headers[i].x = headers[i - 1].x + headers[i - 1].width + ((i == new_col) ?
798 NEW_COL_SIZE_SLOP
799 : 0) + HMARGIN;
800 }
801
802 void
803 _view::insert_pkg (packagemeta & pkg)
804 {
805 pick_line line;
806 line.set_line (&pkg);
807 packagedb db;
808 if (view_mode != VIEW_CATEGORY)
809 {
810 if (lines == NULL)
811 {
812 lines =
813 (pick_line *) calloc (db.npackages () +
814 db.categories.categories (),
815 sizeof (pick_line));
816 nlines = 0;
817 insert_at (0, line);
818 }
819 else
820 insert_under (0, line);
821 }
822 else
823 {
824 // assert (lines); /* protect against a coding change in future */
825 for (Category * cat = pkg.Categories ().getfirstcategory (); cat;
826 cat = cat->next)
827 {
828 /* insert the package under this category in the list. If this category is not
829 visible, add it */
830 int n = 0;
831 while (n < nlines)
832 {
833 /* this should be a generic call to list_sort_cmp */
834 if (lines[n].get_category ()
835 && cat->name == lines[n].get_category ()->name)
836 {
837 insert_under (n, line);
838 n = nlines;
839 }
840 n++;
841 }
842 if (n == nlines)
843 {
844 /* the category wasn't visible - insert at the end */
845 insert_category (cat, CATEGORY_COLLAPSED);
846 insert_pkg (pkg);
847 }
848 }
849 }
850 }
851
852 void
853 _view::insert_category (Category * cat, int collapsed)
854 {
855 pick_line line;
856 line.set_line (cat);
857 if (lines == NULL)
858 {
859 packagedb db;
860 lines =
861 (pick_line *) malloc ((db.npackages () + db.categories.categories ())
862 * sizeof (pick_line));
863 memset (lines, '\0',
864 (db.npackages () +
865 db.categories.categories ()) * sizeof (pick_line));
866 nlines = 0;
867 insert_at (0, line);
868 if (!collapsed)
869 for (CategoryPackage * catpkg = cat->packages; catpkg;
870 catpkg = catpkg->next)
871 insert_pkg (catpkg->pkg);
872 }
873 else
874 {
875 int n = 0;
876 while (n < nlines)
877 {
878 /* this should be a generic call to list_sort_cmp */
879 if (lines[n].get_category ()
880 && strcasecmp (cat->name, lines[n].get_category ()->name) < 0)
881 {
882 insert_at (n, line);
883 if (!collapsed)
884 for (CategoryPackage * catpkg = cat->packages; catpkg;
885 catpkg = catpkg->next)
886 insert_pkg (catpkg->pkg);
887 n = nlines;
888 }
889 else if (lines[n].get_category () == cat)
890 n = nlines;
891 n++;
892
893 }
894 if (n == nlines)
895 {
896 /* insert at the end */
897 insert_at (n, line);
898 if (!collapsed)
899 for (CategoryPackage * catpkg = cat->packages; catpkg;
900 catpkg = catpkg->next)
901 insert_pkg (catpkg->pkg);
902 }
903 }
904 }
905
906 /* insert a new line at line n */
907 void
908 _view::insert_at (int n, pick_line line)
909 {
910 if (n < 0 || n > nlines)
911 return;
912 memmove (&lines[n + 1], &lines[n], (nlines - n) * sizeof (pick_line));
913 lines[n] = line;
914 nlines++;
915 }
916
917 /* insert a new line in the chooser, at the next depth in from linen */
918 void
919 _view::insert_under (int linen, pick_line line)
920 {
921 int n;
922 /* special case - empty view */
923 if (nlines == 0)
924 {
925 insert_at (0, line);
926 return;
927 }
928 /* perhaps these two are equivalent. FIXME: check for potential insert_under (0,.. calls */
929 else if (linen > nlines)
930 {
931 insert_at (nlines, line);
932 return;
933 }
934 /* part 1 - find the appropriate bucket beginning */
935 if (lines[linen].get_category ())
936 {
937 n = linen + 1;
938 }
939 else if (lines[linen].get_pkg ())
940 {
941 n = linen;
942 /* walk up to the beginning of the bucket */
943 while (n > 0 && lines[n - 1].get_pkg ())
944 n--;
945 }
946 else
947 {
948 /* nlines != 0 and lines[linen] is not a category or a package! */
949 return;
950 }
951 /* part 2 - insert in sorted order in the bucket */
952 while (n < nlines)
953 {
954 if (lines[n].get_category () || (lines[n].get_pkg ()
955 && strcasecmp (line.get_pkg ()->name,
956 lines[n].
957 get_pkg ()->name) < 0))
958 {
959 insert_at (n, line);
960 n = nlines;
961 }
962 else if (lines[n].get_pkg () == line.get_pkg ())
963 {
964 n = nlines;
965 }
966 n++;
967 }
968 if (n == nlines)
969 {
970 /* insert at the end of this bucket */
971 insert_at (n, line);
972 }
973 }
974
975 void
976 _view::clear_view (void)
977 {
978 nlines = 0;
979 }
980
981 static views
982 viewsplusplus (views theview)
983 {
984 switch (theview)
985 {
986 case VIEW_UNKNOWN:
987 return VIEW_PACKAGE_FULL;
988 case VIEW_PACKAGE_FULL:
989 return VIEW_PACKAGE;
990 case VIEW_PACKAGE:
991 return VIEW_CATEGORY;
992 case VIEW_CATEGORY:
993 return NVIEW;
994 default:
995 return VIEW_UNKNOWN;
996 }
997 }
998
999 int
1000 _view::click (int row, int x)
1001 {
1002 if (row > nlines)
1003 return 0;
1004 if (lines[row].get_pkg ())
1005 return lines[row].click (x);
1006 else
1007 {
1008 /* if we are the last line or the next line is a category too, expand */
1009 if (row == (nlines - 1) || lines[row + 1].get_category ())
1010 {
1011 int count = nlines;
1012 for (CategoryPackage * catpkg =
1013 lines[row].get_category ()->packages; catpkg;
1014 catpkg = catpkg->next)
1015 {
1016 packagemeta & pkg = catpkg->pkg;
1017 int n = row + 1;
1018 pick_line line;
1019 line.set_line (&pkg);
1020 /* this is a nasty hack. It will go away when the hierarchy is coded */
1021 while (n < nlines)
1022 {
1023 if (lines[n].get_category () || (lines[n].get_pkg ()
1024 && strcasecmp (pkg.name,
1025 lines
1026 [n].get_pkg
1027 ()->name) <
1028 0))
1029 {
1030 insert_at (n, line);
1031 n = nlines;
1032 }
1033 else if (lines[n].get_pkg () == &pkg)
1034 {
1035 n = nlines;
1036 }
1037 n++;
1038 }
1039 if (n == nlines)
1040 {
1041 /* insert at the end of this category */
1042 insert_at (n, line);
1043 n = nlines + 1;
1044 }
1045 }
1046 return nlines - count;
1047 }
1048 else
1049 /* contract */
1050 {
1051 int count = 0, n = row + 1;
1052 while (n < nlines & !lines[n].get_category ())
1053 {
1054 memmove (&lines[n], &lines[n + 1],
1055 (nlines - n) * sizeof (pick_line));
1056 nlines--;
1057 count++;
1058 }
1059 return -count;
1060 }
1061 }
1062 }
1063
1064
1065 static void
1066 set_view_mode (HWND h, views mode)
1067 {
1068 chooser->set_view_mode (mode);
1069
1070 chooser->clear_view ();
1071 packagedb db;
1072 switch (chooser->get_view_mode ())
1073 {
1074 case VIEW_PACKAGE:
1075 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1076 pkg = db.getnextpackage ())
1077 if ((!pkg->desired && pkg->installed) || (pkg->desired && (pkg->desired->srcpicked
1078 || pkg->desired->binpicked)))
1079 chooser->insert_pkg (*pkg);
1080 break;
1081 case VIEW_PACKAGE_FULL:
1082 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1083 pkg = db.getnextpackage ())
1084 chooser->insert_pkg (*pkg);
1085 break;
1086 case VIEW_CATEGORY:
1087 /* start collapsed. TODO: make this a chooser flag */
1088 for (Category * cat = db.categories.getfirstcategory (); cat;
1089 cat = cat->next)
1090 chooser->insert_category (cat, CATEGORY_COLLAPSED);
1091 break;
1092 default:
1093 break;
1094 }
1095
1096 RECT r;
1097 GetClientRect (h, &r);
1098 SCROLLINFO si;
1099 memset (&si, 0, sizeof (si));
1100 si.cbSize = sizeof (si);
1101 si.fMask = SIF_ALL;
1102 si.nMin = 0;
1103 si.nMax =
1104 chooser->headers[chooser->last_col].x +
1105 chooser->headers[chooser->last_col].width + HMARGIN;
1106 si.nPage = r.right;
1107 SetScrollInfo (h, SB_HORZ, &si, TRUE);
1108
1109 si.nMax = chooser->nlines * row_height;
1110 si.nPage = r.bottom - header_height;
1111 SetScrollInfo (h, SB_VERT, &si, TRUE);
1112
1113 scroll_ulc_x = scroll_ulc_y = 0;
1114
1115 InvalidateRect (h, &r, TRUE);
1116
1117 if (nextbutton)
1118 SetFocus (nextbutton);
1119 }
1120
1121 static void
1122 create_listview (HWND dlg, RECT * r)
1123 {
1124 lv = CreateWindowEx (WS_EX_CLIENTEDGE,
1125 "listview",
1126 "listviewwindow",
1127 WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE,
1128 r->left, r->top,
1129 r->right - r->left + 1, r->bottom - r->top + 1,
1130 dlg,
1131 (HMENU) MAKEINTRESOURCE (IDC_CHOOSE_LIST),
1132 hinstance, 0);
1133 ShowWindow (lv, SW_SHOW);
1134 HDC dc = GetDC (lv);
1135 sysfont = GetStockObject (DEFAULT_GUI_FONT);
1136 SelectObject (dc, sysfont);
1137 GetTextMetrics (dc, &tm);
1138 header_height = tm.tmHeight + 5 + 3;
1139
1140 bitmap_dc = CreateCompatibleDC (dc);
1141
1142 row_height = (tm.tmHeight + tm.tmExternalLeading + ROW_MARGIN);
1143 int irh = tm.tmExternalLeading + tm.tmDescent + 11 + ROW_MARGIN;
1144 if (row_height < irh)
1145 row_height = irh;
1146
1147 chooser = new (view) (VIEW_CATEGORY, dc);
1148
1149 default_trust (lv, TRUST_CURR);
1150 set_view_mode (lv, VIEW_CATEGORY);
1151 if (!SetDlgItemText (dlg, IDC_CHOOSE_VIEWCAPTION, chooser->mode_caption ()))
1152 log (LOG_BABBLE, "Failed to set View button caption %ld",
1153 GetLastError ());
1154 packagedb db;
1155 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1156 pkg = db.getnextpackage ())
1157 add_required (*pkg);
1158 /* FIXME: do we need to init the desired fields ? */
1159 static int ta[] = { IDC_CHOOSE_CURR, 0 };
1160 rbset (dlg, ta, IDC_CHOOSE_CURR);
1161
1162 ReleaseDC (lv, dc);
1163 }
1164
1165 static BOOL
1166 dialog_cmd (HWND h, int id, HWND hwndctl, UINT code)
1167 {
1168 packagedb db;
1169 switch (id)
1170 {
1171 case IDC_CHOOSE_PREV:
1172 default_trust (lv, TRUST_PREV);
1173 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1174 pkg = db.getnextpackage ())
1175 add_required (*pkg);
1176 set_view_mode (lv, chooser->get_view_mode ());
1177 break;
1178 case IDC_CHOOSE_CURR:
1179 default_trust (lv, TRUST_CURR);
1180 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1181 pkg = db.getnextpackage ())
1182 add_required (*pkg);
1183 set_view_mode (lv, chooser->get_view_mode ());
1184 break;
1185 case IDC_CHOOSE_EXP:
1186 default_trust (lv, TRUST_TEST);
1187 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1188 pkg = db.getnextpackage ())
1189 add_required (*pkg);
1190 set_view_mode (lv, chooser->get_view_mode ());
1191 break;
1192 case IDC_CHOOSE_VIEW:
1193 set_view_mode (lv, viewsplusplus (chooser->get_view_mode ()));
1194 if (!SetDlgItemText
1195 (h, IDC_CHOOSE_VIEWCAPTION, chooser->mode_caption ()))
1196 log (LOG_BABBLE, "Failed to set View button caption %ld",
1197 GetLastError ());
1198 break;
1199
1200 case IDOK:
1201 if (source == IDC_SOURCE_CWD)
1202 NEXT (IDD_S_INSTALL);
1203 else
1204 NEXT (IDD_S_DOWNLOAD);
1205 break;
1206
1207 case IDC_BACK:
1208 initialized = 0;
1209 if (source == IDC_SOURCE_CWD)
1210 NEXT (IDD_LOCAL_DIR);
1211 else
1212 NEXT (IDD_SITE);
1213 break;
1214
1215 case IDCANCEL:
1216 NEXT (0);
1217 break;
1218 }
1219 return 0;
1220 }
1221
1222 static void
1223 GetParentRect (HWND parent, HWND child, RECT * r)
1224 {
1225 POINT p;
1226 GetWindowRect (child, r);
1227 p.x = r->left;
1228 p.y = r->top;
1229 ScreenToClient (parent, &p);
1230 r->left = p.x;
1231 r->top = p.y;
1232 p.x = r->right;
1233 p.y = r->bottom;
1234 ScreenToClient (parent, &p);
1235 r->right = p.x;
1236 r->bottom = p.y;
1237 }
1238
1239 static BOOL CALLBACK
1240 dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
1241 {
1242 HWND frame;
1243 RECT r;
1244 switch (message)
1245 {
1246 case WM_INITDIALOG:
1247 nextbutton = GetDlgItem (h, IDOK);
1248 frame = GetDlgItem (h, IDC_LISTVIEW_POS);
1249 choose_inst_text = GetDlgItem (h, IDC_CHOOSE_INST_TEXT);
1250 if (source == IDC_SOURCE_DOWNLOAD)
1251 SetWindowText (choose_inst_text, "Select packages to download ");
1252 else
1253 SetWindowText (choose_inst_text, "Select packages to install ");
1254 GetParentRect (h, frame, &r);
1255 r.top += 2;
1256 r.bottom -= 2;
1257 create_listview (h, &r);
1258 #if 0
1259 load_dialog (h);
1260 #endif
1261 return TRUE;
1262 case WM_COMMAND:
1263 return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd);
1264 }
1265 return FALSE;
1266 }
1267
1268 char *
1269 base (const char *s)
1270 {
1271 if (!s)
1272 return 0;
1273 const char *rv = s;
1274 while (*s)
1275 {
1276 if ((*s == '/' || *s == ':' || *s == '\\') && s[1])
1277 rv = s + 1;
1278 s++;
1279 }
1280 return (char *) rv;
1281 }
1282
1283 int
1284 find_tar_ext (const char *path)
1285 {
1286 char *end = strchr (path, '\0');
1287 /* check in longest first order */
1288 char *ext = strstr (path, ".tar.bz2");
1289 if (ext)
1290 return (end - ext) == 8 ? ext - path : 0;
1291 if ((ext = strstr (path, ".tar.gz")));
1292 return (end - ext) == 7 ? ext - path : 0;
1293 if ((ext = strstr (path, ".tar")));
1294 return (end - ext) == 4 ? ext - path : 0;
1295 }
1296
1297 /* Parse a filename into package, version, and extension components. */
1298 int
1299 parse_filename (const char *in_fn, fileparse & f)
1300 {
1301 char *p, *ver;
1302 char fn[strlen (in_fn) + 1];
1303
1304 strcpy (fn, in_fn);
1305 int n = find_tar_ext (fn);
1306
1307 if (!n)
1308 return 0;
1309
1310 strcpy (f.tail, fn + n);
1311 fn[n] = '\0';
1312 f.pkg[0] = f.what[0] = '\0';
1313 p = base (fn);
1314 for (ver = p; *ver; ver++)
1315 if (*ver == '-' || *ver == '_')
1316 if (isdigit (ver[1]))
1317 {
1318 *ver++ = 0;
1319 strcpy (f.pkg, p);
1320 break;
1321 }
1322 else if (strcasecmp (ver, "-src") == 0 ||
1323 strcasecmp (ver, "-patch") == 0)
1324 {
1325 *ver++ = 0;
1326 strcpy (f.pkg, p);
1327 strcpy (f.what, strlwr (ver));
1328 strcpy (f.pkgtar, p);
1329 strcat (f.pkgtar, f.tail);
1330 ver = strchr (ver, '\0');
1331 break;
1332 }
1333
1334 if (!f.pkg[0])
1335 strcpy (f.pkg, p);
1336
1337 if (!f.what[0])
1338 {
1339 int n;
1340 p = strchr (ver, '\0');
1341 strcpy (f.pkgtar, in_fn);
1342 if ((p -= 4) >= ver && strcasecmp (p, "-src") == 0)
1343 n = 4;
1344 else if ((p -= 2) >= ver && strcasecmp (p, "-patch") == 0)
1345 n = 6;
1346 else
1347 n = 0;
1348 if (n)
1349 {
1350 strcpy (f.what, p + 1);
1351 *p = '\0';
1352 p = f.pkgtar + (p - fn) + n;
1353 memmove (p - n, p, strlen (p));
1354 }
1355 }
1356
1357 strcpy (f.ver, *ver ? ver : "0.0");
1358 return 1;
1359 }
1360
1361 /* Find out where to put existing tar file in local directory in
1362 known package array. */
1363 static void
1364 scan2 (char *path, unsigned int size)
1365 {
1366 packagemeta *pkg;
1367 fileparse f;
1368
1369 if (!parse_filename (path, f))
1370 return;
1371
1372 if (f.what[0] != '\0' && f.what[0] != 's')
1373 return;
1374
1375 packagedb db;
1376 pkg = db.getpackagebyname (f.pkg);
1377 if (pkg == NULL)
1378 return;
1379
1380 /* Scan existing package list looking for a match between a known
1381 package and a tar archive on disk.
1382 While scanning, keep track of appropriate "holes" in the trust
1383 table where a tar file could be put if no known entry
1384 exists.
1385
1386 We have 4 specific insertion points and one generic point.
1387 The generic point is in versioned order in the package version array.
1388 The specific points are
1389 *installed
1390 *prev
1391 *curr
1392 *exp.
1393
1394 if the version number matches a version in the db,
1395 we simply add this as a mirror source to that version.
1396 If it matches no version, we add a new version to the db.
1397
1398 Lastly if the version number does not matche one of installed/prev/current/exp
1399 AND we had to create a new version entry
1400 we apply the following heuristic:
1401 if there is no exp, we link this in exp.
1402 If there is an exp and this is higher, we link this in exp, and
1403 if there is no curr, bump what was in exp to curr. If there was a curr, we leave it be.
1404 if this is lower than exp, and there is no curr, link as curr. If there is a curr, leave it be.
1405 If this is lower than curr, and there is no prev, link as prev, if there is a prev, leave it be.
1406
1407 Whilst this logic is potentially wrong from time to time, it guarantees that
1408 setup.ini defined stability won't be altered unintentially. An alternative is to
1409 mark setup.ini defined prev/curr/exp packages as such, when this algorithm, can
1410 get smarter.
1411
1412 So, if setup.ini knows that ash-20010425-1.tar.gz is the current
1413 version and there is an ash-20010426-1.tar.gz in the current directory,
1414 the 20010426 version will be placed in the "test" slot, assuming that
1415 there is no test version listed in setup.ini. */
1416
1417 int added = 0;
1418 for (size_t n = 1; n <= pkg->versions.number (); n++)
1419 {
1420 if (!strcasecmp (f.ver, pkg->versions.getnth (n)->Canonical_version ()))
1421 {
1422 /* FIXME: Add a mirror entry */
1423 added = 1;
1424 }
1425 }
1426 if (!added)
1427 {
1428 /* FIXME: Add a new version */
1429
1430 /* And now the hole finder */
1431 #if 0
1432 if (!pkg->exp)
1433 pkg->exp = thenewver;
1434 else if (strcasecmp (f.ver, pkg->versions[n]->Canonicalversion ()) < 0)
1435 /* try curr */
1436 if (!pkg->curr)
1437 pkg->curr = thenewver;
1438 else if (strcasecmp (f.ver, pkg->versions[n]->Canonicalversion ()) <
1439 0)
1440 /* try prev */
1441 if (!pkg->prev)
1442 pkg->prev = thenewver;
1443 #endif
1444 }
1445
1446 }
1447
1448 static void
1449 scan_downloaded_files ()
1450 {
1451 find (".", scan2);
1452 }
1453
1454 _Info::_Info (const char *_install, const char *_version, int _install_size,
1455 const char *_source, int _source_size)
1456 {
1457 memset (this, 0, sizeof (*this));
1458 install = strdup (_install);
1459 version = strdup (_version);
1460 install_size = _install_size;
1461 if (_source)
1462 {
1463 source = strdup (_source);
1464 source_size = _source_size;
1465 }
1466 }
1467
1468 int
1469 package_sort (const void *va, const void *vb)
1470 {
1471 packagemeta *a = (packagemeta *) va;
1472 packagemeta *b = (packagemeta *) vb;
1473 return strcasecmp (a->name, b->name);
1474 }
1475
1476 void
1477 do_choose (HINSTANCE h)
1478 {
1479 int rv;
1480
1481 nextbutton = 0;
1482 bm_spin = LoadImage (h, MAKEINTRESOURCE (IDB_SPIN), IMAGE_BITMAP, 0, 0, 0);
1483 bm_rtarrow = LoadImage (h, MAKEINTRESOURCE (IDB_RTARROW), IMAGE_BITMAP,
1484 0, 0, 0);
1485
1486 bm_checkyes = LoadImage (h, MAKEINTRESOURCE (IDB_CHECK_YES), IMAGE_BITMAP,
1487 0, 0, 0);
1488 bm_checkno = LoadImage (h, MAKEINTRESOURCE (IDB_CHECK_NO), IMAGE_BITMAP,
1489 0, 0, 0);
1490 bm_checkna = LoadImage (h, MAKEINTRESOURCE (IDB_CHECK_NA), IMAGE_BITMAP,
1491 0, 0, 0);
1492
1493 register_windows (h);
1494
1495 if (source == IDC_SOURCE_DOWNLOAD || source == IDC_SOURCE_CWD)
1496 scan_downloaded_files ();
1497
1498 set_existence ();
1499 fill_missing_category ();
1500
1501 rv = DialogBox (h, MAKEINTRESOURCE (IDD_CHOOSE), 0, dialog_proc);
1502 if (rv == -1)
1503 fatal (IDS_DIALOG_FAILED);
1504
1505 log (LOG_BABBLE, "Chooser results...");
1506 packagedb db;
1507 for (packagemeta * pkg = db.getfirstpackage (); pkg;
1508 pkg = db.getnextpackage ())
1509 {
1510 // static const char *infos[] = { "nada", "prev", "curr", "test" };
1511 const char *trust = ((pkg->desired == pkg->prev) ? "prev"
1512 : (pkg->desired == pkg->curr) ? "curr"
1513 : (pkg->desired == pkg->exp) ? "test" : "unknown");
1514 const char *action = choose_caption (pkg);
1515 const char *installed =
1516 pkg->installed ? pkg->installed->Canonical_version () : "none";
1517
1518 log (LOG_BABBLE, "[%s] action=%s trust=%s installed=%s"
1519 " src?=%s",
1520 pkg->name, action, trust, installed,
1521 pkg->desired && pkg->desired->srcpicked ? "yes" : "no");
1522 if (pkg->Categories ().categories ())
1523 {
1524 /* List categories the package belongs to */
1525 int categories_len = 0;
1526 Category *cp;
1527 for (cp = pkg->Categories ().getfirstcategory (); cp; cp = cp->next)
1528 if (cp->name)
1529 categories_len += strlen (cp->name) + 2;
1530
1531 if (categories_len > 0)
1532 {
1533 char *categories = (char *) malloc (categories_len);
1534 strcpy (categories,
1535 pkg->Categories ().getfirstcategory ()->name);
1536 for (cp = pkg->Categories ().getfirstcategory ()->next; cp;
1537 cp = cp->next)
1538 if (cp->name)
1539 {
1540 strcat (categories, ", ");
1541 strcat (categories, cp->name);
1542 }
1543 log (LOG_BABBLE, " categories=%s", categories);
1544 free (categories);
1545 }
1546 }
1547 if (pkg->desired && pkg->desired->required)
1548 {
1549 /* List other packages this package depends on */
1550 int requires_len = 0;
1551 Dependency *dp;
1552 for (dp = pkg->desired->required; dp; dp = dp->next)
1553 if (dp->package)
1554 requires_len += strlen (dp->package) + 2;
1555
1556 if (requires_len > 0)
1557 {
1558 char *requires = (char *) malloc (requires_len);
1559 strcpy (requires, pkg->desired->required->package);
1560 for (dp = pkg->desired->required->next; dp; dp = dp->next)
1561 if (dp->package)
1562 {
1563 strcat (requires, ", ");
1564 strcat (requires, dp->package);
1565 }
1566 log (LOG_BABBLE, " requires=%s", requires);
1567 free (requires);
1568 }
1569 }
1570 #if 0
1571
1572 /* FIXME: Reinstate this code, but spit out all mirror sites */
1573
1574 for (int t = 1; t < NTRUST; t++)
1575 {
1576 if (pkg->info[t].install)
1577 log (LOG_BABBLE, " [%s] ver=%s\n"
1578 " inst=%s %d exists=%s\n"
1579 " src=%s %d exists=%s",
1580 infos[t],
1581 pkg->info[t].version ? : "(none)",
1582 pkg->info[t].install ? : "(none)",
1583 pkg->info[t].install_size,
1584 (pkg->info[t].install_exists) ? "yes" : "no",
1585 pkg->info[t].source ? : "(none)",
1586 pkg->info[t].source_size,
1587 (pkg->info[t].source_exists) ? "yes" : "no");
1588 }
1589 #endif
1590 }
1591 }
This page took 0.197163 seconds and 5 git commands to generate.