PackageManager: Bug fix
[reactos.git] / rosapps / packmgr / lib / package.cpp
1 ////////////////////////////////////////////////////////
2 //
3 // package.cpp
4 //
5 // package related functions
6 //
7 //
8 // Maarten Bosma, 09.01.2004
9 // maarten.paul@bosma.de
10 //
11 ////////////////////////////////////////////////////////////////////
12
13 #include "package.hpp"
14 #include "expat.h"
15 #include "log.h"
16
17 int PML_XmlDownload (const char* url, void* usrdata, XML_StartElementHandler start,
18 XML_EndElementHandler end, XML_CharacterDataHandler text=0);
19
20
21 // expat callback for start of a package tag
22 void pack_start (void* usrdata, const char* tag, const char** arg)
23 {
24 int i, id;
25 PACKAGE* pack = (PACKAGE*)usrdata;
26
27 // if the tag is a script tag ...
28 if(!strcmp(tag, "scripts"))
29 {
30 // ... read the arguments
31 for (i=0; arg[i]; i+=2)
32 {
33 if(!strcmp(arg[i], "inst"))
34 id = 0;
35
36 else if(!strcmp(arg[i], "update"))
37 id = 1;
38
39 else if(!strcmp(arg[i], "uinst"))
40 id = 2;
41
42 else if(!strcmp(arg[i], "srcinst"))
43 id = 3;
44
45 else
46 continue;
47
48 pack->files[id] = new char [strlen(arg[i+1])+1];
49 strcpy(pack->files[id], arg[i+1]);
50 }
51 }
52
53 // ... save the field
54 else
55 {
56 if(!strcmp(tag, "name"))
57 pack->field = &pack->name;
58
59 else if(!strcmp(tag, "description"))
60 pack->field = &pack->description;
61
62 else if (!strcmp(tag, "depent"))
63 {
64 pack->depencies.push_back((char*)NULL);
65 pack->field = &pack->depencies.back();
66 }
67 }
68 }
69
70 // expat callback for end of a package tag
71 void pack_end (void* usrdata, const char* tag)
72 {
73 PACKAGE* pack = (PACKAGE*)usrdata;
74
75 pack->field = NULL;
76 }
77
78 // expat callback for text
79 void pack_text (void* usrdata, const char* data, int len)
80 {
81 PACKAGE* pack = (PACKAGE*)usrdata;
82
83 if(!pack->field)
84 return;
85
86 *pack->field = new char[len+1];
87 strncpy(*pack->field, data, len);
88 (*pack->field)[len] = '\0';
89 }
90
91 // The user clicks on a package
92 extern "C" int PML_LoadPackage (TREE* tree, int id, PML_SetButton SetButton)
93 {
94 PACKAGE* pack = &tree->packages[id];
95 tree->setButton = SetButton;
96
97 if(SetButton)
98 {
99 SetButton(1, pack->action);
100 SetButton(2, pack->inst); // && pack->action != 0
101 SetButton(3, pack->src_inst);
102 SetButton(4, pack->update);
103 SetButton(5, pack->uninstall);
104 }
105
106 // root notes (like network) return here
107 if(!pack->path)
108 return 1;
109
110 if(!pack->loaded)
111 {
112 PML_XmlDownload (pack->path, (void*)pack, pack_start, pack_end, pack_text);
113 pack->loaded = TRUE;
114 }
115
116 return ERR_OK;
117 }
118
119 extern "C" int PML_FindItem (TREE* tree, const char* what)
120 {
121 int i, j;
122 bool found;
123
124 // if we have children, same action for them
125 for (i=1; (UINT)i<tree->packages.size(); i++)
126 {
127 found = true;
128
129 for(j=0; (UINT)j<strlen(what); j++)
130 {
131 if(tolower(what[j]) != tolower(tree->packages[i].name[j]))
132 {
133 found = false;
134 break;
135 }
136 }
137
138 if(found)
139 return i;
140 }
141
142 return 0;
143 }
144
145 // The user chooses a actions like Install
146 extern "C" int PML_SetAction (TREE* tree, int id, int action, PML_SetIcon SetIcon, PML_Ask Ask)
147 {
148 UINT i;
149 int ret = ERR_OK;
150
151 tree->setIcon = SetIcon;
152 PACKAGE* pack = &tree->packages[id];
153
154 // if we have children, same action for them
155 for (i=0; i<pack->children.size(); i++)
156 ret = ret || PML_SetAction(tree, pack->children[i], action, SetIcon, Ask);
157
158 // is the action possible ?
159 if(!pack->actions[action])
160 return ERR_GENERIC;
161
162 // is it already set
163 if(pack->action == action)
164 return ERR_OK;
165
166 //
167 if(pack->depencies.size() && action)
168 {
169 UINT count = pack->depencies.size();
170 WCHAR buffer[2000], buffer2[200];
171 wcscpy(buffer, PML_TransError(ERR_DEP1));
172
173 for (i=0; i<pack->depencies.size(); i++)
174 {
175 int item = PML_FindItem(tree, pack->depencies[i]);
176
177 if(!item)
178 return ERR_GENERIC;
179
180 if(action == tree->packages[item].action)// || tree->packages[item].installed
181 {
182 count--;
183 continue;
184 }
185
186 MultiByteToWideChar (CP_ACP, 0, pack->depencies[i], strlen(pack->depencies[i])+1, buffer2, 200);
187 wsprintf(buffer, L"%s - %s\n", buffer, buffer2);//
188 }
189
190 wcscat(buffer, PML_TransError(ERR_DEP2));
191
192 if(count)
193 {
194 if(!Ask(buffer))
195 return ERR_GENERIC;
196
197 for (i=0; i<pack->depencies.size(); i++)
198 {
199 int item = PML_FindItem(tree, pack->depencies[i]);
200
201 tree->packages[item].neededBy.push_back(id);
202
203 PML_SetAction(tree, item, action, SetIcon, Ask);
204 }
205 }
206 }
207
208 // load it if it's not loaded yet
209 else if (!pack->loaded && pack->path)
210 {
211 PML_XmlDownload (pack->path, (void*)pack, pack_start, pack_end, pack_text);
212 pack->loaded = TRUE;
213
214 return PML_SetAction(tree, id, action, SetIcon, Ask);
215 }
216
217 // set the icon
218 if(SetIcon && !pack->icon)
219 SetIcon(id, action);
220
221 // set the button(s)
222 if(tree->setButton && action != 2)
223 {
224 tree->setButton(1, action);
225 //tree->setButton(pack->action+1, action);
226 }
227
228 // can't do src install yet
229 if(action == 2)
230 {
231 MessageBox(0, L"Sorry, but source install is not implemented yet.", 0,0);
232 return ERR_OK;
233 }
234
235 // everything but undoing is done here
236 else if (action != 0)
237 {
238 // since we are setting a action we undo it again
239 if(tree->setButton)
240 tree->setButton(1, 1);
241 //tree->setButton(action+1, 0);
242
243 pack->action = action;
244
245 // root notes (like network) return here
246 if(!pack->path)
247 return ret;
248
249 // save the name of the corresponding script in a vector
250 tree->todo.push_back(pack->files[action-1]);
251 }
252
253 // undoing
254 else
255 {
256 for(i=0; i<pack->neededBy.size(); i++)
257 {
258 if(tree->packages[pack->neededBy[i]].action)
259 {
260 SetIcon(id, pack->action);
261 return ERR_GENERIC;
262 }
263 }
264
265 // set action back
266 pack->action = 0;
267
268 // root notes (like network) return here
269 if(!pack->path || pack->action==0)
270 return ret;
271
272 // erase from todo list
273 for(i=0; i<tree->todo.size(); i++)
274 if(!strcmp(tree->todo[i], pack->files[pack->action-1])) // look for right entry
275 tree->todo.erase(tree->todo.begin()+i); // delete it
276 }
277
278 return ret;
279 }
280
281 //
282 extern "C" char* PML_GetDescription (TREE* tree, int id)
283 {
284 PML_LoadPackage(tree, id, NULL);
285
286 return tree->packages[id].description;
287 }
288