1 /*
2  * $LynxId: LYList.c,v 1.55 2020/02/23 21:20:05 tom Exp $
3  *
4  *			Lynx Document Reference List Support	      LYList.c
5  *			====================================
6  *
7  *	Author: FM	Foteos Macrides (macrides@sci.wfbr.edu)
8  *
9  */
10 
11 #include <HTUtils.h>
12 #include <HTAlert.h>
13 #include <LYUtils.h>
14 #include <GridText.h>
15 #include <HTParse.h>
16 #include <LYList.h>
17 #include <LYMap.h>
18 #include <LYClean.h>
19 #include <LYGlobalDefs.h>
20 #include <LYCharUtils.h>
21 #include <LYCharSets.h>
22 #include <LYStrings.h>
23 #include <LYHistory.h>
24 
25 #ifdef DIRED_SUPPORT
26 #include <LYUpload.h>
27 #include <LYLocal.h>
28 #endif /* DIRED_SUPPORT */
29 
30 #include <LYexit.h>
31 #include <LYLeaks.h>
32 
33 /*	showlist - F.Macrides (macrides@sci.wfeb.edu)
34  *	--------
35  *	Create a temporary text/html file with a list of links to
36  *	HyperText References in the current document.
37  *
38  *  On entry
39  *	titles		Set:	if we want titles where available
40  *			Clear:	we only get addresses.
41  */
42 
showlist(DocInfo * newdoc,int titles)43 int showlist(DocInfo *newdoc, int titles)
44 {
45     int cnt;
46     int refs, hidden_links;
47     int result;
48     static char tempfile[LY_MAXPATH];
49     static BOOLEAN last_titles = TRUE;
50     FILE *fp0;
51     char *Address = NULL, *Title = NULL, *cp = NULL;
52     char *LinkTitle = NULL;	/* Rel stored as property of link, not of dest */
53     BOOLEAN intern_w_post = FALSE;
54     const char *desc = "unknown field or link";
55     void *helper;
56 
57     refs = HText_sourceAnchors(HTMainText);
58     hidden_links = HText_HiddenLinkCount(HTMainText);
59     if (refs <= 0 && hidden_links > 0 &&
60 	LYHiddenLinks != HIDDENLINKS_SEPARATE) {
61 	HTUserMsg(NO_VISIBLE_REFS_FROM_DOC);
62 	return (-1);
63     }
64     if (refs <= 0 && hidden_links <= 0) {
65 	HTUserMsg(NO_REFS_FROM_DOC);
66 	return (-1);
67     }
68 
69     if ((fp0 = InternalPageFP(tempfile, titles == last_titles)) == 0)
70 	return (-1);
71 
72     LYLocalFileToURL(&(newdoc->address), tempfile);
73 
74     LYRegisterUIPage(newdoc->address,
75 		     titles ? UIP_LIST_PAGE : UIP_ADDRLIST_PAGE);
76     last_titles = (BOOLEAN) titles;
77     LYforce_HTML_mode = TRUE;	/* force this file to be HTML */
78     LYforce_no_cache = TRUE;	/* force this file to be new */
79 
80 #ifdef USE_ADDRLIST_PAGE
81     if (titles != TRUE)
82 	BeginInternalPage(fp0, ADDRLIST_PAGE_TITLE, LIST_PAGE_HELP);
83     else
84 #endif
85 	BeginInternalPage(fp0, LIST_PAGE_TITLE, LIST_PAGE_HELP);
86 
87     StrAllocCopy(Address, HTLoadedDocumentURL());
88     LYEntify(&Address, FALSE);
89     fprintf(fp0, "%s%s<p>\n", gettext("References in "),
90 	    (non_empty(Address)
91 	     ? Address
92 	     : gettext("this document:")));
93     FREE(Address);
94     if (refs > 0) {
95 	fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
96 					"ol" : "ul"));
97 	if (hidden_links > 0)
98 	    fprintf(fp0, "<lh><em>%s</em>\n", gettext("Visible links:"));
99     }
100     if (hidden_links > 0) {
101 	if (LYHiddenLinks == HIDDENLINKS_IGNORE)
102 	    hidden_links = 0;
103     }
104     helper = NULL;		/* init */
105     result = 1;
106     for (cnt = 1; cnt <= refs; cnt++) {
107 	HTChildAnchor *child = HText_childNextNumber(cnt, &helper);
108 	int value = HText_findAnchorNumber(helper);
109 	HTAnchor *dest_intl = NULL;
110 	HTAnchor *dest;
111 	HTParentAnchor *parent;
112 	char *address;
113 	const char *title;
114 
115 	if (child == 0) {
116 	    /*
117 	     * child should not be 0 unless form field numbering is on and cnt
118 	     * is the number of a form input field.  HText_FormDescNumber()
119 	     * will set desc to a description of what type of input field this
120 	     * is.  We'll list it to ensure that the link numbers on the list
121 	     * page match the numbering in the original document, but won't
122 	     * create a forward link to the form.  - FM && LE
123 	     *
124 	     * Changed to create a fake hidden link, to get the numbering right
125 	     * in connection with always treating this file as
126 	     * HIDDENLINKS_MERGE in GridText.c - kw
127 	     */
128 	    if (fields_are_numbered()) {
129 		HText_FormDescNumber(cnt, &desc);
130 		fprintf(fp0,
131 			"<li><a id=%d href=\"#%d\">form field</a> = <em>%s</em>\n",
132 			cnt, cnt, desc);
133 	    }
134 	} else if (value >= result) {
135 	    if (track_internal_links)
136 		dest_intl = HTAnchor_followTypedLink(child, HTInternalLink);
137 	    dest = (dest_intl
138 		    ? dest_intl
139 		    : HTAnchor_followLink(child));
140 	    parent = HTAnchor_parent(dest);
141 	    if (!intern_w_post && dest_intl &&
142 		HTMainAnchor &&
143 		HTMainAnchor->post_data &&
144 		parent->post_data &&
145 		BINEQ(HTMainAnchor->post_data, parent->post_data)) {
146 		/*
147 		 * Set flag to note that we had at least one internal link, if
148 		 * the document from which we are generating the list has
149 		 * associated POST data; after an extra check that the link
150 		 * destination really has the same POST data so that we can
151 		 * believe it is an internal link.
152 		 */
153 		intern_w_post = TRUE;
154 	    }
155 	    address = HTAnchor_address(dest);
156 	    title = titles ? HTAnchor_title(parent) : NULL;
157 	    if (dest_intl) {
158 		HTSprintf0(&LinkTitle, "(internal)");
159 	    } else if (titles && child->type &&
160 		       dest == child->dest &&
161 		       !StrNCmp(HTAtom_name(child->type),
162 				"RelTitle: ", 10)) {
163 		HTSprintf0(&LinkTitle, "(%s)", HTAtom_name(child->type) + 10);
164 	    } else {
165 		FREE(LinkTitle);
166 	    }
167 	    StrAllocCopy(Address, address);
168 	    FREE(address);
169 	    LYEntify(&Address, TRUE);
170 	    if (non_empty(title)) {
171 		LYformTitle(&Title, title);
172 		LYEntify(&Title, TRUE);
173 		if (*Title) {
174 		    cp = findPoundSelector(Address);
175 		} else {
176 		    FREE(Title);
177 		}
178 	    }
179 
180 	    fprintf(fp0, "<li><a href=\"%s\"%s>%s%s%s%s%s</a>\n", Address,
181 		    dest_intl ? " TYPE=\"internal link\"" : "",
182 		    NonNull(LinkTitle),
183 		    ((HTAnchor *) parent != dest) && Title ? "in " : "",
184 		    (char *) (Title ? Title : Address),
185 		    (Title && cp) ? " - " : "",
186 		    (Title && cp) ? (cp + 1) : "");
187 
188 	    FREE(Address);
189 	    FREE(Title);
190 	}
191 	result = value + 1;
192     }
193     FREE(LinkTitle);
194 
195     if (hidden_links > 0) {
196 	if (refs > 0)
197 	    fprintf(fp0, "\n</%s>\n\n<p>\n",
198 		    ((keypad_mode == NUMBERS_AS_ARROWS) ?
199 		     "ol" : "ul"));
200 	fprintf(fp0, "<%s compact>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
201 					"ol continue" : "ul"));
202 	fprintf(fp0, "<lh><em>%s</em>\n", gettext("Hidden links:"));
203     }
204 
205     for (cnt = 0; cnt < hidden_links; cnt++) {
206 	StrAllocCopy(Address, HText_HiddenLinkAt(HTMainText, cnt));
207 	LYEntify(&Address, FALSE);
208 	if (isEmpty(Address)) {
209 	    FREE(Address);
210 	    continue;
211 	}
212 	fprintf(fp0, "<li><a href=\"%s\">%s</a>\n", Address, Address);
213 
214 	FREE(Address);
215     }
216 
217     fprintf(fp0, "\n</%s>\n", ((keypad_mode == NUMBERS_AS_ARROWS) ?
218 			       "ol" : "ul"));
219     EndInternalPage(fp0);
220     LYCloseTempFP(fp0);
221 
222     /*
223      * Make necessary changes to newdoc before returning to caller.  If the
224      * intern_w_post flag is set, we keep the POST data in newdoc that have
225      * been passed in.  They should be the same as in the loaded document for
226      * which we generated the list.  In that case the file we have written will
227      * be associated with the same POST data when it is loaded after we are
228      * done here, so that following one of the links we have marked as
229      * "internal link" can lead back to the underlying document with the right
230      * address+post_data combination.  - kw
231      */
232     if (intern_w_post) {
233 	newdoc->internal_link = TRUE;
234     } else {
235 	LYFreePostData(newdoc);
236 	newdoc->internal_link = FALSE;
237     }
238     newdoc->isHEAD = FALSE;
239     newdoc->safe = FALSE;
240     return (0);
241 }
242 
print_refs(FILE * fp,int titles,int refs)243 static int print_refs(FILE *fp, int titles, int refs)
244 {
245     int result = 0;
246     int cnt;
247     int value;
248     char *address = NULL;
249     const char *desc = gettext("unknown field or link");
250     void *helper = NULL;	/* init */
251 
252     for (cnt = 1; cnt <= refs; cnt++) {
253 	HTChildAnchor *child = HText_childNextNumber(cnt, &helper);
254 	HTAnchor *dest;
255 	HTParentAnchor *parent;
256 	const char *title;
257 	int counter = result + 1;
258 
259 	if (child == 0) {
260 	    /*
261 	     * child should not be 0 unless form field numbering is on and
262 	     * cnt is the number of a form input field.
263 	     * HText_FormDescNumber() will set desc to a description of
264 	     * what type of input field this is.  We'll create a
265 	     * within-document link to ensure that the link numbers on the
266 	     * list page match the numbering in the original document, but
267 	     * won't create a forward link to the form.  - FM && LE
268 	     */
269 	    if (fields_are_numbered()) {
270 		HText_FormDescNumber(cnt, &desc);
271 		fprintf(fp, "%4d. form field = %s\n", counter, desc);
272 	    }
273 	} else {
274 	    dest = HTAnchor_followLink(child);
275 	    /*
276 	     * Ignore if child anchor points to itself, i.e., we had something
277 	     * like <A NAME=xyz HREF="#xyz"> and it is not treated as a hidden
278 	     * link.  Useful if someone 'P'rints the List Page (which isn't a
279 	     * very useful action to do, but anyway...) - kw
280 	     */
281 	    if (dest != (HTAnchor *) child) {
282 		parent = HTAnchor_parent(dest);
283 		title = titles ? HTAnchor_title(parent) : NULL;
284 		if (links_are_numbered()) {
285 		    value = HText_findAnchorNumber(helper);
286 		    if (value <= result)
287 			continue;
288 		    fprintf(fp, "%4d. ", value);
289 		}
290 		if (((HTAnchor *) parent != dest) && title) {
291 		    fprintf(fp, "in ");
292 		}
293 		if (title) {
294 		    fprintf(fp, "%s\n", title);
295 		} else {
296 		    address = HTAnchor_short_address(dest);
297 		    if (dump_links_decoded
298 			&& LYCharSet_UC[current_char_set].enc == UCT_ENC_UTF8) {
299 			(void) HTUnEscape(address);
300 		    }
301 		    fprintf(fp, "%s\n", address);
302 		    FREE(address);
303 		}
304 	    }
305 	}
306 	if (counter > result)
307 	    result = counter;
308 #ifdef VMS
309 	if (HadVMSInterrupt)
310 	    break;
311 #endif /* VMS */
312     }
313     return result;
314 }
315 
print_hidden_refs(FILE * fp,int refs,int hidden_links)316 static void print_hidden_refs(FILE *fp, int refs, int hidden_links)
317 {
318     int cnt;
319     char *address = NULL;
320 
321     fprintf(fp, "%s   %s\n", ((refs > 0) ? "\n" : ""),
322 	    gettext("Hidden links:"));
323     for (cnt = 0; cnt < hidden_links; cnt++) {
324 	StrAllocCopy(address, HText_HiddenLinkAt(HTMainText, cnt));
325 	if (isEmpty(address)) {
326 	    FREE(address);
327 	    continue;
328 	}
329 
330 	if (links_are_numbered())
331 	    fprintf(fp, "%4d. ", ((cnt + 1) + refs));
332 	fprintf(fp, "%s\n", address);
333 	FREE(address);
334 #ifdef VMS
335 	if (HadVMSInterrupt)
336 	    break;
337 #endif /* VMS */
338     }
339 }
340 
341 /*	printlist - F.Macrides (macrides@sci.wfeb.edu)
342  *	---------
343  *	Print a text/plain list of HyperText References
344  *	in the current document.
345  *
346  *  On entry
347  *	titles		Set:	if we want titles where available
348  *			Clear:	we only get addresses.
349  */
printlist(FILE * fp,int titles)350 void printlist(FILE *fp, int titles)
351 {
352     int refs, hidden_links;
353 
354     refs = HText_sourceAnchors(HTMainText);
355     if (refs > 0 || LYHiddenLinks == HIDDENLINKS_SEPARATE) {
356 	hidden_links = HText_HiddenLinkCount(HTMainText);
357 	if (refs > 0 || hidden_links > 0) {
358 	    if (links_are_numbered() || fields_are_numbered())
359 		fprintf(fp, "\n%s\n\n", gettext("References"));
360 	    if (LYHiddenLinks == HIDDENLINKS_IGNORE)
361 		hidden_links = 0;
362 	    if (hidden_links > 0) {
363 		fprintf(fp, "   %s\n", gettext("Visible links:"));
364 	    }
365 	    refs = print_refs(fp, titles, refs) + 1;
366 
367 	    if (hidden_links > 0) {
368 		print_hidden_refs(fp, refs, hidden_links);
369 	    }
370 	}
371     }
372     LYPrintImgMaps(fp);
373     return;
374 }
375