1 /*								       HTIcon.c
2 **	ICON MANAGEMENT
3 **
4 **	(c) COPYRIGHT MIT 1995.
5 **	Please first read the full copyright statement in the file COPYRIGH.
6 **	@(#) $Id$
7 **
8 **	This module contains the functions for initializing, adding
9 **	and selecting the icon for local directory listings, FTP and Gopher.
10 **
11 **	History:
12 **	   Mar 94	Written by Ari Luotonen, luotonen@dxcern.cern.ch
13 **			Henrik Frystyk, frystyk@w3.org
14 **
15 */
16 
17 /* Library include files */
18 #include "wwwsys.h"
19 #include "WWWUtil.h"
20 #include "WWWCore.h"
21 #include "HTIcons.h"					 /* Implemented here */
22 
23 struct _HTIconNode {
24     char *	icon_url;
25     char *	icon_alt;
26     char *	type_templ;
27 };
28 
29 /* Globals */
30 PRIVATE HTIconNode * icon_unknown = NULL;	/* Unknown file type */
31 PRIVATE HTIconNode * icon_blank = NULL;		/* Blank icon in heading */
32 PRIVATE HTIconNode * icon_parent = NULL;	/* Parent directory icon */
33 PRIVATE HTIconNode * icon_dir = NULL;		/* Directory icon */
34 
35 /* Type definitions and global variables etc. local to this module */
36 PRIVATE HTList * icons = NULL;
37 PRIVATE int alt_len = 0;			/* Longest ALT text */
38 
39 /* ------------------------------------------------------------------------- */
40 
alt_resize(char * alt)41 PRIVATE void alt_resize (char * alt)
42 {
43     if (alt) {
44 	int len = strlen(alt);
45 	if (len > alt_len) alt_len = len;
46     }
47 }
48 
match(char * templ,const char * actual)49 PRIVATE BOOL match (char * templ,
50 		    const char * actual)
51 {
52     static char * c1 = NULL;
53     static char * c2 = NULL;
54     char * slash1;
55     char * slash2;
56 
57     StrAllocCopy(c1,templ);
58     StrAllocCopy(c2,actual);
59 
60     slash1 = strchr(c1,'/');
61     slash2 = strchr(c2,'/');
62 
63     if (slash1 && slash2) {
64 	*slash1++ = 0;
65 	*slash2++ = 0;
66 	return HTStrMatch(c1,c2) && HTStrMatch(slash1,slash2);
67     }
68     else if (!slash1 && !slash2)
69 	return HTStrMatch(c1,c2) ? YES : NO;
70     else
71 	return NO;
72 }
73 
74 
prefixed(const char * name,const char * prefix)75 PRIVATE char * prefixed (const char * name, const char * prefix)
76 {
77     char * ret = NULL;
78     if (name) {
79 	int len = prefix ? strlen(prefix) : 0;
80 	if ((ret = (char *) HT_MALLOC(len + strlen(name) + 2)) == NULL)
81 	    HT_OUTOFMEM("prefixed");
82 	if (prefix) {
83 	    strcpy(ret, prefix);
84 	    if (*prefix && prefix[len-1] != '/') strcat(ret, "/");
85 	    strcat(ret, name);
86 	} else
87 	    strcpy(ret, name);
88     }
89     return ret;
90 }
91 
HTIcon_url(HTIconNode * node)92 PUBLIC char * HTIcon_url (HTIconNode * node)
93 {
94     return node ? node->icon_url : NULL;
95 }
96 
97 /*
98 **	Returned string must be freed by caller
99 */
HTIcon_alternative(HTIconNode * node,BOOL brackets)100 PUBLIC char * HTIcon_alternative (HTIconNode * node, BOOL brackets)
101 {
102     char * ret = NULL;
103     if (node) {
104 	char * p = NULL;
105 	int len = node->icon_alt ? strlen(node->icon_alt) : 0;
106 	if ((p = ret = (char *) HT_MALLOC(alt_len + 3)) == NULL)
107 	    HT_OUTOFMEM("HTIcon_alt_string");
108 	*p++ = brackets ? '[' : ' ';
109 	if (node->icon_alt) strcpy(p, node->icon_alt);
110 	p += len;
111 	while (len++ < alt_len) *p++=' ';
112 	*p++ = brackets ? ']' : ' ';
113 	*p = 0;
114     }
115     return ret;
116 }
117 
118 /*
119 **	HTAddIcon(url, alt, type_templ) adds icon:
120 **
121 **		<IMG SRC="url" ALT="[alt]">
122 **
123 **	for files for which content-type or content-encoding matches
124 **	type_templ.  If type_templ contains a slash, it is taken to be
125 **	a content-type template.  Otherwise, it is a content-encoding
126 **	template.
127 */
HTIcon_add(const char * url,const char * prefix,char * alt,char * type_templ)128 PUBLIC BOOL HTIcon_add (const char * url, const char * prefix,
129 			char * alt, char * type_templ)
130 {
131     if (url && type_templ) {
132 	HTIconNode * node;
133 	if ((node = (HTIconNode *) HT_CALLOC(1,sizeof(HTIconNode))) == NULL)
134 	    HT_OUTOFMEM("HTAddIcon");
135 	if (url) node->icon_url = prefixed(url, prefix);
136 	if (alt) StrAllocCopy(node->icon_alt, alt);
137 	if (type_templ) StrAllocCopy(node->type_templ, type_templ);
138 	if (!icons) icons = HTList_new();
139 	HTList_addObject(icons, (void *) node);
140 	alt_resize(alt);
141 	HTTRACE(PROT_TRACE, "AddIcon..... %s => SRC=\"%s\" ALT=\"%s\"\n" _
142 		    type_templ _ url _ alt ? alt : "");
143 	return YES;
144     }
145     return NO;
146 }
147 
148 /*
149 **	Add the icon used for files for which
150 **	no other icon seems appropriate (unknown type).
151 */
HTIcon_addUnknown(const char * url,const char * prefix,char * alt)152 PUBLIC BOOL HTIcon_addUnknown (const char * url, const char * prefix,
153 			       char * alt)
154 {
155     if ((icon_unknown = (HTIconNode *) HT_CALLOC(1,sizeof(HTIconNode)))==NULL)
156         HT_OUTOFMEM("HTAddUnknownIcon");
157     if (url) icon_unknown->icon_url = prefixed(url, prefix);
158     if (alt) StrAllocCopy(icon_unknown->icon_alt, alt);
159     alt_resize(alt);
160     HTTRACE(PROT_TRACE, "Icon add.... UNKNOWN => SRC=\"%s\" ALT=\"%s\"\n" _ url _
161 		alt ? alt : "");
162     return YES;
163 }
164 
165 
166 /*
167 **	Add the blank icon used in the heading of the listing.
168 */
HTIcon_addBlank(const char * url,const char * prefix,char * alt)169 PUBLIC BOOL HTIcon_addBlank (const char * url, const char * prefix, char * alt)
170 {
171     if ((icon_blank = (HTIconNode *) HT_CALLOC(1,sizeof(HTIconNode))) == NULL)
172         HT_OUTOFMEM("HTAddBlankIcon");
173     if (url) icon_blank->icon_url = prefixed(url, prefix);
174     if (alt) StrAllocCopy(icon_blank->icon_alt, alt);
175     alt_resize(alt);
176     HTTRACE(PROT_TRACE, "Icon add.... BLANK => SRC=\"%s\" ALT=\"%s\"\n" _ url _
177 		alt ? alt : "");
178     return YES;
179 }
180 
181 
182 /*
183 **	Add the parent directory icon.
184 */
HTIcon_addParent(const char * url,const char * prefix,char * alt)185 PUBLIC BOOL HTIcon_addParent (const char * url, const char * prefix, char * alt)
186 {
187     if ((icon_parent = (HTIconNode *) HT_CALLOC(1,sizeof(HTIconNode))) == NULL)
188         HT_OUTOFMEM("HTAddBlankIcon");
189     if (url) icon_parent->icon_url = prefixed(url, prefix);
190     if (alt) StrAllocCopy(icon_parent->icon_alt, alt);
191     alt_resize(alt);
192     HTTRACE(PROT_TRACE, "Icon add.... PARENT => SRC=\"%s\" ALT=\"%s\"\n" _ url _
193 		alt ? alt : "");
194     return YES;
195 }
196 
197 
198 /*
199 **	Add the directory icon.
200 */
HTIcon_addDir(const char * url,const char * prefix,char * alt)201 PUBLIC BOOL HTIcon_addDir (const char * url, const char * prefix, char * alt)
202 {
203     if ((icon_dir = (HTIconNode *) HT_CALLOC(1,sizeof(HTIconNode))) == NULL)
204         HT_OUTOFMEM("HTAddBlankIcon");
205     if (url) icon_dir->icon_url = prefixed(url, prefix);
206     if (alt) StrAllocCopy(icon_dir->icon_alt, alt);
207     alt_resize(alt);
208     HTTRACE(PROT_TRACE, "Icon add.... DIRECTORY => SRC=\"%s\" ALT=\"%s\"\n" _ url _
209 		alt ? alt : "");
210     return YES;
211 }
212 
213 /*
214 **	Returns the icon corresponding to content_type or content_encoding.
215 **	If no match is found then use "unknown icon"
216 */
HTIcon_find(HTFileMode mode,HTFormat content_type,HTEncoding content_encoding)217 PUBLIC HTIconNode * HTIcon_find (HTFileMode	mode,
218 				 HTFormat	content_type,
219 				 HTEncoding	content_encoding)
220 {
221     if (!icon_unknown) icon_unknown = icon_blank;
222     if (mode == HT_IS_FILE) {
223 	const char * ct = content_type ? HTAtom_name(content_type) : NULL;
224 	const char * ce = content_encoding ? HTAtom_name(content_encoding) : NULL;
225 	HTList * cur = icons;
226 	HTIconNode * node;
227 
228 	while ((node = (HTIconNode*)HTList_nextObject(cur))) {
229 	    char * slash = strchr(node->type_templ,'/');
230 	    if ((ct && slash && match(node->type_templ,ct)) ||
231 		(ce && !slash && HTStrMatch(node->type_templ,ce))) {
232 		return node;
233 	    }
234 	}
235     } else if (mode == HT_IS_DIR) {
236 	return icon_dir ? icon_dir : icon_unknown;
237     } else if (mode == HT_IS_BLANK) {
238 	return icon_blank ? icon_blank : icon_unknown;
239     } else if (mode == HT_IS_PARENT) {
240 	return icon_parent ? icon_parent : icon_unknown;
241     }
242     return icon_unknown;
243 }
244 
HTIconNode_delete(HTIconNode * pNode)245 PRIVATE void HTIconNode_delete (HTIconNode* pNode)
246 {
247     if (pNode) {
248       HT_FREE(pNode->icon_url);
249       HT_FREE(pNode->icon_alt);
250       HT_FREE(pNode->type_templ);
251       HT_FREE(pNode);
252     }
253 }
254 /*
255 **  cleans up all memory used by icons. Should be called by
256 **  HTLibTerminate() (but it isn't)
257 **
258 */
HTIcon_deleteAll(void)259 PUBLIC void HTIcon_deleteAll (void)
260 {
261     if(icons != NULL) {
262 	HTList * iconList = icons;
263 	HTIconNode * node;
264 	while((node = (HTIconNode*)HTList_removeLastObject(iconList))) {
265 	  HTIconNode_delete(node);
266 	}
267 	/* delete the list as well */
268 	HTList_delete(icons);
269 	icons = NULL;
270     }
271     HTIconNode_delete(icon_unknown);
272     icon_unknown = NULL;
273     HTIconNode_delete(icon_blank);
274     icon_blank = NULL;
275     HTIconNode_delete(icon_parent);
276     icon_parent = NULL;
277     HTIconNode_delete(icon_dir);
278     icon_dir = NULL;
279 }
280