Merge lp:~dangarner/xibo/1.2.2-pre into lp:xibo/1.2

Proposed by Dan Garner
Status: Merged
Merged at revision: 213
Proposed branch: lp:~dangarner/xibo/1.2.2-pre
Merge into: lp:xibo/1.2
Diff against target: 1513 lines (+770/-99)
24 files modified
client/dotNET/CacheManager.cs (+75/-1)
client/dotNET/FileCollector.cs (+50/-29)
client/dotNET/MainForm.cs (+45/-22)
client/dotNET/Properties/Settings.Designer.cs (+13/-1)
client/dotNET/Properties/Settings.settings (+4/-1)
client/dotNET/Region.cs (+6/-7)
client/dotNET/RequiredFiles.cs (+206/-0)
client/dotNET/Schedule.cs (+1/-1)
client/dotNET/ScheduleManager.cs (+16/-1)
client/dotNET/Web References/xmds/Reference.cs (+67/-0)
client/dotNET/Web References/xmds/xmds.wsdl (+23/-0)
client/dotNET/XiboClient.csproj (+1/-0)
client/dotNET/app.config (+4/-1)
client/dotNET/bin/Release/XiboClient.exe.config (+4/-1)
client/dotNET/bin/Release/XiboClient.vshost.exe.config (+4/-1)
server/install/database/27.sql (+9/-0)
server/lib/app/kit.class.php (+9/-13)
server/lib/data/display.data.class.php (+60/-16)
server/lib/data/schedule.data.class.php (+5/-0)
server/lib/pages/display.class.php (+74/-4)
server/lib/pages/layout.class.php (+6/-0)
server/lib/pages/region.class.php (+5/-0)
server/lib/service/service.wsdl (+23/-0)
server/lib/service/xmdssoap.class.php (+60/-0)
To merge this branch: bzr merge lp:~dangarner/xibo/1.2.2-pre
Reviewer Review Type Date Requested Status
Xibo Maintainters Pending
Review via email: mp+51554@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'client/dotNET/CacheManager.cs'
2--- client/dotNET/CacheManager.cs 2010-04-19 21:45:10 +0000
3+++ client/dotNET/CacheManager.cs 2011-02-28 15:09:32 +0000
4@@ -25,6 +25,7 @@
5 using System.Windows.Forms;
6 using System.Xml.Serialization;
7 using System.Diagnostics;
8+using System.Xml;
9
10 namespace XiboClient
11 {
12@@ -173,7 +174,7 @@
13 /// </summary>
14 /// <param name="path"></param>
15 /// <returns>True is it is and false if it isnt</returns>
16- public bool IsValid(String path)
17+ public bool IsValidPath(String path)
18 {
19 // TODO: what makes a path valid?
20 // Currently a path is valid if it is in the cache
21@@ -185,6 +186,10 @@
22 {
23 if (file.path == path)
24 {
25+ // If we cached it over 2 minutes ago, then check the GetLastWriteTime
26+ if (file.cacheDate > DateTime.Now.AddMinutes(-2))
27+ return true;
28+
29 try
30 {
31 // Check to see if this file has been modified since the MD5 cache
32@@ -209,6 +214,75 @@
33 // Reached the end of the cache and havent found the file.
34 return false;
35 }
36+
37+ /// <summary>
38+ /// Is the provided layout file a valid layout (has all media)
39+ /// </summary>
40+ /// <param name="layoutFile"></param>
41+ /// <returns></returns>
42+ public bool IsValidLayout(string layoutFile)
43+ {
44+ Debug.WriteLine("Checking Layout " + layoutFile + " is valid");
45+
46+ if (!IsValidPath(layoutFile))
47+ return false;
48+
49+ // Load the XLF, get all media ID's
50+ XmlDocument layoutXml = new XmlDocument();
51+ layoutXml.Load(Properties.Settings.Default.LibraryPath + @"\" + layoutFile);
52+
53+ XmlNodeList mediaNodes = layoutXml.SelectNodes("//media");
54+
55+ foreach (XmlNode media in mediaNodes)
56+ {
57+ // Is this a stored media type?
58+ switch (media.Attributes["type"].Value)
59+ {
60+ case "video":
61+ case "image":
62+ case "flash":
63+ case "ppt":
64+
65+ // Get the path and see if its valid
66+ if (!IsValidPath(media.InnerText))
67+ return false;
68+
69+ break;
70+
71+ default:
72+ continue;
73+ }
74+ }
75+
76+ return true;
77+ }
78+
79+ /// <summary>
80+ /// Regenerate from Required Files
81+ /// </summary>
82+ public void Regenerate()
83+ {
84+ if (!File.Exists(Application.UserAppDataPath + "\\" + Properties.Settings.Default.RequiredFilesFile))
85+ return;
86+
87+ // Open the XML file and check each required file that isnt already there
88+ XmlDocument xml = new XmlDocument();
89+ xml.Load(Application.UserAppDataPath + "\\" + Properties.Settings.Default.RequiredFilesFile);
90+
91+ XmlNodeList fileNodes = xml.SelectNodes("//RequiredFile/Path");
92+
93+ foreach (XmlNode file in fileNodes)
94+ {
95+ string path = file.InnerText;
96+
97+ // Does the file exist?
98+ if (!File.Exists(Properties.Settings.Default.LibraryPath + @"\" + path))
99+ continue;
100+
101+ // Add this file to the cache manager
102+ Add(path, GetMD5(path));
103+ }
104+ }
105 }
106
107 public struct Md5Resource
108
109=== modified file 'client/dotNET/FileCollector.cs'
110--- client/dotNET/FileCollector.cs 2011-01-30 18:13:32 +0000
111+++ client/dotNET/FileCollector.cs 2011-02-28 15:09:32 +0000
112@@ -31,28 +31,26 @@
113 class FileCollector
114 {
115 private CacheManager _cacheManager;
116+ private RequiredFiles _requiredFiles;
117+ private XmlDocument _xml;
118
119 public FileCollector(CacheManager cacheManager, string xmlString)
120 {
121 _cacheManager = cacheManager;
122
123- xml = new XmlDocument();
124+ // Load the XML file RF call
125+ _xml = new XmlDocument();
126+ _xml.LoadXml(xmlString);
127
128- try
129- {
130- xml.LoadXml(xmlString);
131- }
132- catch (Exception e)
133- {
134- //Log this error
135- System.Diagnostics.Debug.WriteLine(e.Message);
136- }
137+ // Create a required files object
138+ _requiredFiles = new RequiredFiles();
139+ _requiredFiles.RequiredFilesXml = _xml;
140
141 // Get the key for later use
142 hardwareKey = new HardwareKey();
143
144 // Make a new filelist collection
145- files = new Collection<FileList>();
146+ _files = new Collection<RequiredFile>();
147
148 // Create a webservice call
149 xmdsFile = new XiboClient.xmds.xmds();
150@@ -73,13 +71,13 @@
151 /// </summary>
152 public void CompareAndCollect()
153 {
154- XmlNodeList fileNodes = xml.SelectNodes("/files/file");
155+ XmlNodeList fileNodes = _xml.SelectNodes("/files/file");
156
157 //Inspect each file we have here
158 foreach (XmlNode file in fileNodes)
159 {
160 XmlAttributeCollection attributes = file.Attributes;
161- FileList fileList = new FileList();
162+ RequiredFile fileList = new RequiredFile();
163
164 if (attributes["type"].Value == "layout")
165 {
166@@ -120,13 +118,15 @@
167 fileList.md5 = attributes["md5"].Value;
168 fileList.retrys = 0;
169
170- files.Add(fileList);
171+ _files.Add(fileList);
172 }
173 else
174 {
175 // The MD5 of the current file and the MD5 in RequiredFiles are the same.
176 // Therefore make sure this MD5 is in the CacheManager
177 _cacheManager.Add(path + ".xlf", md5);
178+
179+ _requiredFiles.MarkComplete(int.Parse(path), md5);
180 }
181 }
182 else
183@@ -141,7 +141,7 @@
184 fileList.md5 = attributes["md5"].Value;
185 fileList.retrys = 0;
186
187- files.Add(fileList);
188+ _files.Add(fileList);
189 }
190 }
191 else if (attributes["type"].Value == "media")
192@@ -183,13 +183,16 @@
193 fileList.md5 = attributes["md5"].Value;
194 fileList.retrys = 0;
195
196- files.Add(fileList);
197+ _files.Add(fileList);
198 }
199 else
200 {
201 // The MD5 of the current file and the MD5 in RequiredFiles are the same.
202 // Therefore make sure this MD5 is in the CacheManager
203 _cacheManager.Add(path, md5);
204+
205+ string[] filePart = path.Split('.');
206+ _requiredFiles.MarkComplete(int.Parse(filePart[0]), md5);
207 }
208 }
209 else
210@@ -205,7 +208,7 @@
211 fileList.md5 = attributes["md5"].Value;
212 fileList.retrys = 0;
213
214- files.Add(fileList);
215+ _files.Add(fileList);
216 }
217 }
218 else if (attributes["type"].Value == "blacklist")
219@@ -234,18 +237,24 @@
220 }
221 }
222
223- Debug.WriteLine(String.Format("There are {0} files to get", files.Count.ToString()));
224+ Debug.WriteLine(String.Format("There are {0} files to get", _files.Count.ToString()));
225
226 // Output a list of the files we need to get
227 string debugMessage = "";
228
229- foreach (FileList fileToGet in files)
230+ foreach (RequiredFile fileToGet in _files)
231 debugMessage += string.Format("File: {0}, Type: {1}, MD5: {2}. ", fileToGet.path, fileToGet.type, fileToGet.md5);
232
233 Debug.WriteLine(debugMessage);
234
235+ // Report the files files back to XMDS
236+ _requiredFiles.ReportInventory();
237+
238+ // Write Required Files
239+ _requiredFiles.WriteRequiredFiles();
240+
241 // Is there anything to get?
242- if (files.Count == 0)
243+ if (_files.Count == 0)
244 {
245 CollectionComplete();
246 return;
247@@ -255,7 +264,7 @@
248 _currentFile = 0;
249
250 // Preload the first filelist
251- _currentFileList = files[_currentFile];
252+ _currentFileList = _files[_currentFile];
253
254 // Get the first file
255 GetFile();
256@@ -375,6 +384,10 @@
257 {
258 // Add to the CacheManager
259 _cacheManager.Add(_currentFileList.path + ".xlf", md5sum);
260+
261+ // Report this completion back to XMDS
262+ _requiredFiles.MarkComplete(int.Parse(_currentFileList.path), md5sum);
263+ _requiredFiles.ReportInventory();
264 }
265
266 // Fire a layout complete event
267@@ -445,6 +458,11 @@
268
269 System.Diagnostics.Debug.WriteLine(string.Format("File downloaded: {0}", _currentFileList.path));
270
271+ // Report this completion back to XMDS
272+ string[] filePart = _currentFileList.path.Split('.');
273+ _requiredFiles.MarkComplete(int.Parse(filePart[0]), md5sum);
274+ _requiredFiles.ReportInventory();
275+
276 // All the file has been recieved. Move on to the next file.
277 _currentFile++;
278 }
279@@ -475,13 +493,16 @@
280 /// </summary>
281 public void GetFile()
282 {
283- if (_currentFile > (files.Count - 1))
284+ if (_currentFile > (_files.Count - 1))
285 {
286- System.Diagnostics.Debug.WriteLine(String.Format("Finished Recieving {0} files", files.Count));
287+ System.Diagnostics.Debug.WriteLine(String.Format("Finished Receiving {0} files", _files.Count));
288
289 // Clean up
290- files.Clear();
291- xmdsFile.Dispose();
292+ _files.Clear();
293+ xmdsFile.Dispose();
294+
295+ // Write Required Files
296+ _requiredFiles.WriteRequiredFiles();
297
298 // Finished getting this file list
299 CollectionComplete();
300@@ -491,7 +512,7 @@
301 // Get the current file into the currentfilelist if the current one is finished
302 if (_currentFileList.complete)
303 {
304- _currentFileList = files[_currentFile];
305+ _currentFileList = _files[_currentFile];
306 }
307
308 System.Diagnostics.Debug.WriteLine(String.Format("Getting the file : {0} chunk : {1}", _currentFileList.path, _currentFileList.chunkOffset.ToString()));
309@@ -504,7 +525,7 @@
310 }
311
312 [Serializable]
313- private struct FileList
314+ private struct RequiredFile
315 {
316 public string path;
317 public string type;
318@@ -519,9 +540,9 @@
319
320 private XmlDocument xml;
321 private HardwareKey hardwareKey;
322- private Collection<FileList> files;
323+ private Collection<RequiredFile> _files;
324 private int _currentFile;
325- private FileList _currentFileList;
326+ private RequiredFile _currentFileList;
327 private xmds.xmds xmdsFile;
328
329 public event LayoutFileChangedDelegate LayoutFileChanged;
330
331=== modified file 'client/dotNET/MainForm.cs'
332--- client/dotNET/MainForm.cs 2011-01-30 18:13:32 +0000
333+++ client/dotNET/MainForm.cs 2011-02-28 15:09:32 +0000
334@@ -72,14 +72,45 @@
335
336 _statLog = new StatLog();
337
338+ this.FormClosing += new FormClosingEventHandler(MainForm_FormClosing);
339+ this.Shown += new EventHandler(MainForm_Shown);
340+ }
341+
342+ /// <summary>
343+ /// Called after the form has been shown
344+ /// </summary>
345+ /// <param name="sender"></param>
346+ /// <param name="e"></param>
347+ void MainForm_Shown(object sender, EventArgs e)
348+ {
349+ // Process any stuff that has happened during the loading process
350+ Application.DoEvents();
351+
352 // Create a cachemanager
353 SetCacheManager();
354
355- this.FormClosing += new FormClosingEventHandler(MainForm_FormClosing);
356+ try
357+ {
358+ // Create the Schedule
359+ _schedule = new Schedule(Application.UserAppDataPath + "\\" + Properties.Settings.Default.ScheduleFile, ref _cacheManager);
360+
361+ // Bind to the schedule change event - notifys of changes to the schedule
362+ _schedule.ScheduleChangeEvent += new Schedule.ScheduleChangeDelegate(schedule_ScheduleChangeEvent);
363+
364+ // Initialize the other schedule components
365+ _schedule.InitializeComponents();
366+ }
367+ catch (Exception ex)
368+ {
369+ Debug.WriteLine(ex.Message, LogType.Error.ToString());
370+ MessageBox.Show("Fatal Error initialising the application", "Fatal Error");
371+ Close();
372+ Dispose();
373+ }
374 }
375
376 /// <summary>
377- /// Called when the form has finished loading
378+ /// Called before the form has loaded for the first time
379 /// </summary>
380 /// <param name="sender"></param>
381 /// <param name="e"></param>
382@@ -96,30 +127,13 @@
383 Cursor.Position = new Point(_clientSize.Width, _clientSize.Height);
384 Cursor.Hide();
385
386+ ShowSplashScreen();
387+
388 // Change the default Proxy class
389 OptionForm.SetGlobalProxy();
390
391 // UserApp data
392 Debug.WriteLine(new LogMessage("MainForm_Load", "User AppData Path: " + Application.UserAppDataPath), LogType.Info.ToString());
393-
394- try
395- {
396- // Create the Schedule
397- _schedule = new Schedule(Application.UserAppDataPath + "\\" + Properties.Settings.Default.ScheduleFile, ref _cacheManager);
398-
399- // Bind to the schedule change event - notifys of changes to the schedule
400- _schedule.ScheduleChangeEvent += new Schedule.ScheduleChangeDelegate(schedule_ScheduleChangeEvent);
401-
402- // Initialize the other schedule components
403- _schedule.InitializeComponents();
404- }
405- catch (Exception ex)
406- {
407- Debug.WriteLine(ex.Message, LogType.Error.ToString());
408- MessageBox.Show("Fatal Error initialising the application", "Fatal Error");
409- Close();
410- Dispose();
411- }
412 }
413
414 private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
415@@ -152,11 +166,20 @@
416 }
417 catch (Exception ex)
418 {
419- Trace.WriteLine(new LogMessage("Schedule", "Unable to reuse the Cache Manager because: " + ex.Message));
420+ Trace.WriteLine(new LogMessage("MainForm - SetCacheManager", "Unable to reuse the Cache Manager because: " + ex.Message));
421
422 // Create a new cache manager
423 _cacheManager = new CacheManager();
424 }
425+
426+ try
427+ {
428+ _cacheManager.Regenerate();
429+ }
430+ catch (Exception ex)
431+ {
432+ Trace.WriteLine(new LogMessage("MainForm - SetCacheManager", "Regenerate failed because: " + ex.Message));
433+ }
434 }
435
436 /// <summary>
437
438=== modified file 'client/dotNET/Properties/Settings.Designer.cs'
439--- client/dotNET/Properties/Settings.Designer.cs 2011-02-14 16:21:56 +0000
440+++ client/dotNET/Properties/Settings.Designer.cs 2011-02-28 15:09:32 +0000
441@@ -271,7 +271,7 @@
442
443 [global::System.Configuration.ApplicationScopedSettingAttribute()]
444 [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
445- [global::System.Configuration.DefaultSettingValueAttribute("1.2.1")]
446+ [global::System.Configuration.DefaultSettingValueAttribute("1.2.2")]
447 public string ClientVersion {
448 get {
449 return ((string)(this["ClientVersion"]));
450@@ -370,5 +370,17 @@
451 this["emptyLayoutDuration"] = value;
452 }
453 }
454+
455+ [global::System.Configuration.UserScopedSettingAttribute()]
456+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
457+ [global::System.Configuration.DefaultSettingValueAttribute("requiredFiles.xml")]
458+ public string RequiredFilesFile {
459+ get {
460+ return ((string)(this["RequiredFilesFile"]));
461+ }
462+ set {
463+ this["RequiredFilesFile"] = value;
464+ }
465+ }
466 }
467 }
468
469=== modified file 'client/dotNET/Properties/Settings.settings'
470--- client/dotNET/Properties/Settings.settings 2011-02-14 16:21:56 +0000
471+++ client/dotNET/Properties/Settings.settings 2011-02-28 15:09:32 +0000
472@@ -69,7 +69,7 @@
473 <Value Profile="(Default)">cacheManager.xml</Value>
474 </Setting>
475 <Setting Name="ClientVersion" Type="System.String" Scope="Application">
476- <Value Profile="(Default)">1.2.1</Value>
477+ <Value Profile="(Default)">1.2.2</Value>
478 </Setting>
479 <Setting Name="scrollStepAmount" Type="System.Decimal" Scope="User">
480 <Value Profile="(Default)">1</Value>
481@@ -95,5 +95,8 @@
482 <Setting Name="emptyLayoutDuration" Type="System.Decimal" Scope="User">
483 <Value Profile="(Default)">10</Value>
484 </Setting>
485+ <Setting Name="RequiredFilesFile" Type="System.String" Scope="User">
486+ <Value Profile="(Default)">requiredFiles.xml</Value>
487+ </Setting>
488 </Settings>
489 </SettingsFile>
490\ No newline at end of file
491
492=== modified file 'client/dotNET/Region.cs'
493--- client/dotNET/Region.cs 2010-11-09 21:23:31 +0000
494+++ client/dotNET/Region.cs 2011-02-28 15:09:32 +0000
495@@ -310,12 +310,11 @@
496 }
497
498 // We cannot have a 0 duration here... not sure why we would... but
499- if (options.duration == 0)
500- options.duration = int.Parse(Properties.Settings.Default.emptyLayoutDuration.ToString());
501-
502- // Fail safe
503- if (options.duration == 0)
504- options.duration = 10;
505+ if (options.duration == 0 && options.type != "video")
506+ {
507+ int emptyLayoutDuration = int.Parse(Properties.Settings.Default.emptyLayoutDuration.ToString());
508+ options.duration = (emptyLayoutDuration == 0) ? 10 : emptyLayoutDuration;
509+ }
510
511 // There will be some stuff on option nodes
512 XmlNode optionNode = mediaNode.FirstChild;
513@@ -386,7 +385,7 @@
514 if (options.type == "video" || options.type == "flash" || options.type == "image" || options.type == "powerpoint")
515 {
516 // Use the cache manager to determine if the file is valid
517- validNode = _cacheManager.IsValid(options.uri);
518+ validNode = _cacheManager.IsValidPath(options.uri);
519 }
520 }
521
522
523=== added file 'client/dotNET/RequiredFiles.cs'
524--- client/dotNET/RequiredFiles.cs 1970-01-01 00:00:00 +0000
525+++ client/dotNET/RequiredFiles.cs 2011-02-28 15:09:32 +0000
526@@ -0,0 +1,206 @@
527+/*
528+ * Xibo - Digitial Signage - http://www.xibo.org.uk
529+ * Copyright (C) 2011 Daniel Garner
530+ *
531+ * This file is part of Xibo.
532+ *
533+ * Xibo is free software: you can redistribute it and/or modify
534+ * it under the terms of the GNU Affero General Public License as published by
535+ * the Free Software Foundation, either version 3 of the License, or
536+ * any later version.
537+ *
538+ * Xibo is distributed in the hope that it will be useful,
539+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
540+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
541+ * GNU Affero General Public License for more details.
542+ *
543+ * You should have received a copy of the GNU Affero General Public License
544+ * along with Xibo. If not, see <http://www.gnu.org/licenses/>.
545+ */
546+using System;
547+using System.Collections.Generic;
548+using System.Collections.ObjectModel;
549+using System.Text;
550+using System.IO;
551+using System.Security.Cryptography;
552+using System.Xml;
553+using System.Diagnostics;
554+using System.Windows.Forms;
555+using System.Xml.Serialization;
556+
557+namespace XiboClient
558+{
559+ public class RequiredFiles
560+ {
561+ private XmlDocument _requiredFilesXml;
562+ public Collection<RequiredFile> _requiredFiles;
563+ private xmds.xmds _report;
564+
565+ public RequiredFiles()
566+ {
567+ _requiredFiles = new Collection<RequiredFile>();
568+
569+ // Create a webservice call
570+ _report = new XiboClient.xmds.xmds();
571+
572+ // Start up the Xmds Service Object
573+ _report.Credentials = null;
574+ _report.Url = Properties.Settings.Default.XiboClient_xmds_xmds;
575+ _report.UseDefaultCredentials = false;
576+ }
577+
578+ /// <summary>
579+ /// Set required files from the XML document
580+ /// </summary>
581+ private void SetRequiredFiles()
582+ {
583+ // Itterate through the RF XML and populate the RF collection
584+ XmlNodeList fileNodes = _requiredFilesXml.SelectNodes("/files/file");
585+
586+ foreach (XmlNode file in fileNodes)
587+ {
588+ RequiredFile rf = new RequiredFile();
589+
590+ XmlAttributeCollection attributes = file.Attributes;
591+
592+ rf.FileType = attributes["type"].Value;
593+ rf.Complete = 0;
594+ rf.Md5 = "";
595+ rf.LastChecked = DateTime.Now;
596+
597+ if (rf.FileType == "media")
598+ {
599+ string[] filePart = attributes["path"].Value.Split('.');
600+ rf.Id = int.Parse(filePart[0]);
601+ rf.Path = attributes["path"].Value;
602+ }
603+ else if (rf.FileType == "layout")
604+ {
605+ rf.Id = int.Parse(attributes["path"].Value);
606+ rf.Path = attributes["path"].Value + ".xlf";
607+ }
608+ else
609+ {
610+ continue;
611+ }
612+
613+ _requiredFiles.Add(rf);
614+ }
615+ }
616+
617+ /// <summary>
618+ /// Required Files XML
619+ /// </summary>
620+ public XmlDocument RequiredFilesXml
621+ {
622+ set
623+ {
624+ _requiredFilesXml = value;
625+ SetRequiredFiles();
626+ }
627+ }
628+
629+ /// <summary>
630+ /// Mark a RequiredFile as complete
631+ /// </summary>
632+ /// <param name="id"></param>
633+ /// <param name="md5"></param>
634+ public void MarkComplete(int id, string md5)
635+ {
636+ foreach (RequiredFile rf in _requiredFiles)
637+ {
638+ if (rf.Id == id)
639+ {
640+ RequiredFile newRf = rf;
641+
642+ newRf.Complete = 1;
643+ newRf.Md5 = md5;
644+
645+
646+ _requiredFiles.Add(newRf);
647+ _requiredFiles.Remove(rf);
648+
649+ return;
650+ }
651+ }
652+ }
653+
654+ /// <summary>
655+ /// Mark a RequiredFile as incomplete
656+ /// </summary>
657+ /// <param name="id"></param>
658+ /// <param name="md5"></param>
659+ public void MarkIncomplete(int id, string md5)
660+ {
661+ foreach (RequiredFile rf in _requiredFiles)
662+ {
663+ if (rf.Id == id)
664+ {
665+ RequiredFile newRf = rf;
666+
667+ newRf.Complete = 0;
668+ newRf.Md5 = md5;
669+
670+ _requiredFiles.Add(newRf);
671+ _requiredFiles.Remove(rf);
672+
673+ return;
674+ }
675+ }
676+ }
677+
678+ /// <summary>
679+ /// Writes Required Files to disk
680+ /// </summary>
681+ public void WriteRequiredFiles()
682+ {
683+ Debug.WriteLine(new LogMessage("RequiredFiles - WriteRequiredFiles", "About to Write RequiredFiles"), LogType.Info.ToString());
684+
685+ try
686+ {
687+ using (StreamWriter streamWriter = new StreamWriter(Application.UserAppDataPath + "\\" + Properties.Settings.Default.RequiredFilesFile))
688+ {
689+ XmlSerializer xmlSerializer = new XmlSerializer(typeof(RequiredFiles));
690+
691+ xmlSerializer.Serialize(streamWriter, this);
692+ }
693+ }
694+ catch (Exception ex)
695+ {
696+ System.Diagnostics.Trace.WriteLine(new LogMessage("RequiredFiles - WriteRequiredFiles", "Unable to write RequiredFiles to disk because: " + ex.Message));
697+ }
698+ }
699+
700+ /// <summary>
701+ /// Report Required Files to XMDS
702+ /// </summary>
703+ public void ReportInventory()
704+ {
705+ HardwareKey hardwareKey = new HardwareKey();
706+
707+ // Build the XML required by media file
708+ string xml = "";
709+
710+ foreach (RequiredFile rf in _requiredFiles)
711+ {
712+ xml += string.Format("<file type=\"{0}\" id=\"{1}\" complete=\"{2}\" lastChecked=\"{3}\" md5=\"{4}\" />",
713+ rf.FileType, rf.Id.ToString(), rf.Complete.ToString(), rf.LastChecked.ToString(), rf.Md5);
714+ }
715+
716+ xml = string.Format("<files>{0}</files>", xml);
717+
718+ _report.MediaInventoryAsync(Properties.Settings.Default.Version, Properties.Settings.Default.ServerKey,
719+ hardwareKey.Key, xml);
720+ }
721+ }
722+
723+ public struct RequiredFile
724+ {
725+ public string FileType;
726+ public int Id;
727+ public int Complete;
728+ public DateTime LastChecked;
729+ public string Md5;
730+ public string Path;
731+ }
732+}
733
734=== modified file 'client/dotNET/Schedule.cs'
735--- client/dotNET/Schedule.cs 2010-08-22 16:49:09 +0000
736+++ client/dotNET/Schedule.cs 2011-02-28 15:09:32 +0000
737@@ -74,7 +74,7 @@
738 _cacheManager = cacheManager;
739
740 // Create a schedule manager
741- _scheduleManager = new ScheduleManager(scheduleLocation);
742+ _scheduleManager = new ScheduleManager(_cacheManager, scheduleLocation);
743
744 // Create a new Xmds service object
745 _xmds2 = new XiboClient.xmds.xmds();
746
747=== modified file 'client/dotNET/ScheduleManager.cs'
748--- client/dotNET/ScheduleManager.cs 2010-08-25 21:39:53 +0000
749+++ client/dotNET/ScheduleManager.cs 2011-02-28 15:09:32 +0000
750@@ -42,13 +42,15 @@
751 private Collection<LayoutSchedule> _layoutSchedule;
752 private Collection<LayoutSchedule> _currentSchedule;
753 private bool _refreshSchedule;
754+ private CacheManager _cacheManager;
755
756 /// <summary>
757 /// Creates a new schedule Manager
758 /// </summary>
759 /// <param name="scheduleLocation"></param>
760- public ScheduleManager(string scheduleLocation)
761+ public ScheduleManager(CacheManager cacheManager, string scheduleLocation)
762 {
763+ _cacheManager = cacheManager;
764 _location = scheduleLocation;
765
766 // Create an empty layout schedule
767@@ -178,6 +180,19 @@
768 // For each layout in the schedule determine if it is currently inside the _currentSchedule, and whether it should be
769 foreach (LayoutSchedule layout in _layoutSchedule)
770 {
771+ // Is the layout valid in the cachemanager?
772+ try
773+ {
774+ if (!_cacheManager.IsValidLayout(layout.id + ".xlf"))
775+ continue;
776+ }
777+ catch
778+ {
779+ // TODO: Ignore this layout.. raise an error?
780+ Trace.WriteLine("Unable to determine if layout is valid or not");
781+ continue;
782+ }
783+
784 // If this is the default, skip it
785 if (layout.NodeName == "default")
786 {
787
788=== modified file 'client/dotNET/Web References/xmds/Reference.cs'
789--- client/dotNET/Web References/xmds/Reference.cs 2010-11-09 21:23:31 +0000
790+++ client/dotNET/Web References/xmds/Reference.cs 2011-02-28 15:09:32 +0000
791@@ -45,6 +45,8 @@
792
793 private System.Threading.SendOrPostCallback SubmitStatsOperationCompleted;
794
795+ private System.Threading.SendOrPostCallback MediaInventoryOperationCompleted;
796+
797 private bool useDefaultCredentialsSetExplicitly;
798
799 /// <remarks/>
800@@ -108,6 +110,9 @@
801 public event SubmitStatsCompletedEventHandler SubmitStatsCompleted;
802
803 /// <remarks/>
804+ public event MediaInventoryCompletedEventHandler MediaInventoryCompleted;
805+
806+ /// <remarks/>
807 [System.Web.Services.Protocols.SoapRpcMethodAttribute("urn:xmds#RegisterDisplay", RequestNamespace="urn:xmds", ResponseNamespace="urn:xmds")]
808 [return: System.Xml.Serialization.SoapElementAttribute("ActivationMessage")]
809 public string RegisterDisplay(string serverKey, string hardwareKey, string displayName, string version) {
810@@ -402,6 +407,42 @@
811 }
812
813 /// <remarks/>
814+ [System.Web.Services.Protocols.SoapRpcMethodAttribute("urn:xmds#MediaInventory", RequestNamespace="urn:xmds", ResponseNamespace="urn:xmds")]
815+ [return: System.Xml.Serialization.SoapElementAttribute("success")]
816+ public bool MediaInventory(string version, string serverKey, string hardwareKey, [System.Xml.Serialization.SoapElementAttribute("mediaInventory")] string mediaInventory1) {
817+ object[] results = this.Invoke("MediaInventory", new object[] {
818+ version,
819+ serverKey,
820+ hardwareKey,
821+ mediaInventory1});
822+ return ((bool)(results[0]));
823+ }
824+
825+ /// <remarks/>
826+ public void MediaInventoryAsync(string version, string serverKey, string hardwareKey, string mediaInventory1) {
827+ this.MediaInventoryAsync(version, serverKey, hardwareKey, mediaInventory1, null);
828+ }
829+
830+ /// <remarks/>
831+ public void MediaInventoryAsync(string version, string serverKey, string hardwareKey, string mediaInventory1, object userState) {
832+ if ((this.MediaInventoryOperationCompleted == null)) {
833+ this.MediaInventoryOperationCompleted = new System.Threading.SendOrPostCallback(this.OnMediaInventoryOperationCompleted);
834+ }
835+ this.InvokeAsync("MediaInventory", new object[] {
836+ version,
837+ serverKey,
838+ hardwareKey,
839+ mediaInventory1}, this.MediaInventoryOperationCompleted, userState);
840+ }
841+
842+ private void OnMediaInventoryOperationCompleted(object arg) {
843+ if ((this.MediaInventoryCompleted != null)) {
844+ System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
845+ this.MediaInventoryCompleted(this, new MediaInventoryCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
846+ }
847+ }
848+
849+ /// <remarks/>
850 public new void CancelAsync(object userState) {
851 base.CancelAsync(userState);
852 }
853@@ -627,6 +668,32 @@
854 }
855 }
856 }
857+
858+ /// <remarks/>
859+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.4927")]
860+ public delegate void MediaInventoryCompletedEventHandler(object sender, MediaInventoryCompletedEventArgs e);
861+
862+ /// <remarks/>
863+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "2.0.50727.4927")]
864+ [System.Diagnostics.DebuggerStepThroughAttribute()]
865+ [System.ComponentModel.DesignerCategoryAttribute("code")]
866+ public partial class MediaInventoryCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs {
867+
868+ private object[] results;
869+
870+ internal MediaInventoryCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :
871+ base(exception, cancelled, userState) {
872+ this.results = results;
873+ }
874+
875+ /// <remarks/>
876+ public bool Result {
877+ get {
878+ this.RaiseExceptionIfNecessary();
879+ return ((bool)(this.results[0]));
880+ }
881+ }
882+ }
883 }
884
885 #pragma warning restore 1591
886\ No newline at end of file
887
888=== modified file 'client/dotNET/Web References/xmds/xmds.wsdl'
889--- client/dotNET/Web References/xmds/xmds.wsdl 2010-11-09 21:23:31 +0000
890+++ client/dotNET/Web References/xmds/xmds.wsdl 2011-02-28 15:09:32 +0000
891@@ -81,6 +81,15 @@
892 <wsdl:message name="SubmitStatsResponse">
893 <wsdl:part name="success" type="xsd:boolean" />
894 </wsdl:message>
895+ <wsdl:message name="MediaInventoryRequest">
896+ <wsdl:part name="version" type="xsd:string" />
897+ <wsdl:part name="serverKey" type="xsd:string" />
898+ <wsdl:part name="hardwareKey" type="xsd:string" />
899+ <wsdl:part name="mediaInventory" type="xsd:string" />
900+ </wsdl:message>
901+ <wsdl:message name="MediaInventoryResponse">
902+ <wsdl:part name="success" type="xsd:boolean" />
903+ </wsdl:message>
904 <wsdl:portType name="xmdsPortType">
905 <wsdl:operation name="RegisterDisplay">
906 <documentation>Registered the Display on the Xibo Network</documentation>
907@@ -122,6 +131,11 @@
908 <wsdl:input message="tns:SubmitStatsRequest" />
909 <wsdl:output message="tns:SubmitStatsResponse" />
910 </wsdl:operation>
911+ <wsdl:operation name="MediaInventory">
912+ <documentation>Report back the clients MediaInventory</documentation>
913+ <wsdl:input message="tns:MediaInventoryRequest" />
914+ <wsdl:output message="tns:MediaInventoryResponse" />
915+ </wsdl:operation>
916 </wsdl:portType>
917 <wsdl:binding name="xmdsBinding" type="tns:xmdsPortType">
918 <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc" />
919@@ -197,6 +211,15 @@
920 <soap:body use="encoded" namespace="urn:xmds" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
921 </wsdl:output>
922 </wsdl:operation>
923+ <wsdl:operation name="MediaInventory">
924+ <soap:operation soapAction="urn:xmds#MediaInventory" style="rpc" />
925+ <wsdl:input>
926+ <soap:body use="encoded" namespace="urn:xmds" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
927+ </wsdl:input>
928+ <wsdl:output>
929+ <soap:body use="encoded" namespace="urn:xmds" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
930+ </wsdl:output>
931+ </wsdl:operation>
932 </wsdl:binding>
933 <wsdl:service name="xmds">
934 <wsdl:port name="xmdsPort" binding="tns:xmdsBinding">
935
936=== modified file 'client/dotNET/XiboClient.csproj'
937--- client/dotNET/XiboClient.csproj 2011-02-09 17:15:43 +0000
938+++ client/dotNET/XiboClient.csproj 2011-02-28 15:09:32 +0000
939@@ -161,6 +161,7 @@
940 <Compile Include="Region.cs">
941 <SubType>Component</SubType>
942 </Compile>
943+ <Compile Include="RequiredFiles.cs" />
944 <Compile Include="Rss.cs">
945 <SubType>Form</SubType>
946 </Compile>
947
948=== modified file 'client/dotNET/app.config'
949--- client/dotNET/app.config 2011-02-14 16:21:56 +0000
950+++ client/dotNET/app.config 2011-02-28 15:09:32 +0000
951@@ -79,6 +79,9 @@
952 <setting name="emptyLayoutDuration" serializeAs="String">
953 <value>10</value>
954 </setting>
955+ <setting name="RequiredFilesFile" serializeAs="String">
956+ <value>requiredFiles.xml</value>
957+ </setting>
958 </XiboClient.Properties.Settings>
959 </userSettings>
960 <applicationSettings>
961@@ -102,7 +105,7 @@
962 <value>cacheManager.xml</value>
963 </setting>
964 <setting name="ClientVersion" serializeAs="String">
965- <value>1.2.1</value>
966+ <value>1.2.2</value>
967 </setting>
968 <setting name="xmdsResetTimeout" serializeAs="String">
969 <value>900</value>
970
971=== modified file 'client/dotNET/bin/Release/AxInterop.ShockwaveFlashObjects.dll'
972Binary files client/dotNET/bin/Release/AxInterop.ShockwaveFlashObjects.dll 2010-04-19 21:45:10 +0000 and client/dotNET/bin/Release/AxInterop.ShockwaveFlashObjects.dll 2011-02-28 15:09:32 +0000 differ
973=== modified file 'client/dotNET/bin/Release/AxInterop.WMPLib.dll'
974Binary files client/dotNET/bin/Release/AxInterop.WMPLib.dll 2010-04-19 21:45:10 +0000 and client/dotNET/bin/Release/AxInterop.WMPLib.dll 2011-02-28 15:09:32 +0000 differ
975=== modified file 'client/dotNET/bin/Release/Interop.ShockwaveFlashObjects.dll'
976Binary files client/dotNET/bin/Release/Interop.ShockwaveFlashObjects.dll 2010-04-19 21:45:10 +0000 and client/dotNET/bin/Release/Interop.ShockwaveFlashObjects.dll 2011-02-28 15:09:32 +0000 differ
977=== modified file 'client/dotNET/bin/Release/Interop.WMPLib.dll'
978Binary files client/dotNET/bin/Release/Interop.WMPLib.dll 2010-04-19 21:45:10 +0000 and client/dotNET/bin/Release/Interop.WMPLib.dll 2011-02-28 15:09:32 +0000 differ
979=== modified file 'client/dotNET/bin/Release/XiboClient.exe.config'
980--- client/dotNET/bin/Release/XiboClient.exe.config 2011-02-14 16:21:56 +0000
981+++ client/dotNET/bin/Release/XiboClient.exe.config 2011-02-28 15:09:32 +0000
982@@ -79,6 +79,9 @@
983 <setting name="emptyLayoutDuration" serializeAs="String">
984 <value>10</value>
985 </setting>
986+ <setting name="RequiredFilesFile" serializeAs="String">
987+ <value>requiredFiles.xml</value>
988+ </setting>
989 </XiboClient.Properties.Settings>
990 </userSettings>
991 <applicationSettings>
992@@ -102,7 +105,7 @@
993 <value>cacheManager.xml</value>
994 </setting>
995 <setting name="ClientVersion" serializeAs="String">
996- <value>1.2.1</value>
997+ <value>1.2.2</value>
998 </setting>
999 <setting name="xmdsResetTimeout" serializeAs="String">
1000 <value>900</value>
1001
1002=== modified file 'client/dotNET/bin/Release/XiboClient.vshost.exe.config'
1003--- client/dotNET/bin/Release/XiboClient.vshost.exe.config 2011-02-14 16:21:56 +0000
1004+++ client/dotNET/bin/Release/XiboClient.vshost.exe.config 2011-02-28 15:09:32 +0000
1005@@ -79,6 +79,9 @@
1006 <setting name="emptyLayoutDuration" serializeAs="String">
1007 <value>10</value>
1008 </setting>
1009+ <setting name="RequiredFilesFile" serializeAs="String">
1010+ <value>requiredFiles.xml</value>
1011+ </setting>
1012 </XiboClient.Properties.Settings>
1013 </userSettings>
1014 <applicationSettings>
1015@@ -102,7 +105,7 @@
1016 <value>cacheManager.xml</value>
1017 </setting>
1018 <setting name="ClientVersion" serializeAs="String">
1019- <value>1.2.1</value>
1020+ <value>1.2.2</value>
1021 </setting>
1022 <setting name="xmdsResetTimeout" serializeAs="String">
1023 <value>900</value>
1024
1025=== added file 'server/install/database/27.sql'
1026--- server/install/database/27.sql 1970-01-01 00:00:00 +0000
1027+++ server/install/database/27.sql 2011-02-28 15:09:32 +0000
1028@@ -0,0 +1,9 @@
1029+
1030+ALTER TABLE `display` ADD `MediaInventoryStatus` TINYINT NOT NULL ,
1031+ADD `MediaInventoryXml` LONGTEXT NULL;
1032+
1033+/* VERSION UPDATE */
1034+/* Set the version table, etc */
1035+UPDATE `version` SET `app_ver` = '1.2.2-pre', `XmdsVersion` = 2;
1036+UPDATE `setting` SET `value` = 0 WHERE `setting` = 'PHONE_HOME_DATE';
1037+UPDATE `version` SET `DBVersion` = '27';
1038\ No newline at end of file
1039
1040=== modified file 'server/lib/app/kit.class.php'
1041--- server/lib/app/kit.class.php 2010-12-01 14:49:39 +0000
1042+++ server/lib/app/kit.class.php 2011-02-28 15:09:32 +0000
1043@@ -376,9 +376,7 @@
1044 static function ClassLoader($class)
1045 {
1046 if (class_exists($class))
1047- {
1048- return true;
1049- }
1050+ return;
1051
1052 $class = strtolower($class);
1053
1054@@ -387,28 +385,26 @@
1055 {
1056 include_once('lib/pages/' . $class . '.class.php');
1057 }
1058- elseif (file_exists('lib/data/' . $class . '.data.class.php'))
1059+
1060+ if (file_exists('lib/data/' . $class . '.data.class.php'))
1061 {
1062 include_once('lib/data/' . $class . '.data.class.php');
1063 }
1064- elseif (file_exists('modules/' . $class . '.module.php'))
1065+
1066+ if (file_exists('modules/' . $class . '.module.php'))
1067 {
1068 include_once('modules/' . $class . '.module.php');
1069 }
1070- elseif (file_exists('modules/' . $class . '.php'))
1071+
1072+ if (file_exists('modules/' . $class . '.php'))
1073 {
1074 include_once('modules/' . $class . '.php');
1075 }
1076- elseif (file_exists('lib/service/' . $class . '.class.php'))
1077+
1078+ if (file_exists('lib/service/' . $class . '.class.php'))
1079 {
1080 include_once('lib/service/' . $class . '.class.php');
1081 }
1082- else
1083- {
1084- return false;
1085- }
1086-
1087- return true;
1088 }
1089
1090 /**
1091
1092=== modified file 'server/lib/data/display.data.class.php'
1093--- server/lib/data/display.data.class.php 2011-02-10 20:42:24 +0000
1094+++ server/lib/data/display.data.class.php 2011-02-28 15:09:32 +0000
1095@@ -251,7 +251,7 @@
1096 * @return
1097 * @param $license Object
1098 */
1099- public function Touch($license, $clientAddress = '')
1100+ public function Touch($license, $clientAddress = '', $mediaInventoryComplete = 0, $mediaInventoryXml = '')
1101 {
1102 $db =& $this->db;
1103 $time = time();
1104@@ -266,6 +266,13 @@
1105 if ($clientAddress != '')
1106 $SQL .= sprintf(" , ClientAddress = '%s' ", $db->escape_string($clientAddress));
1107
1108+ // Media Inventory Settings (if appropriate)
1109+ if ($mediaInventoryComplete != 0)
1110+ $SQL .= sprintf(" , MediaInventoryStatus = %d ", $mediaInventoryComplete);
1111+
1112+ if ($mediaInventoryXml != '')
1113+ $SQL .= sprintf(" , MediaInventoryXml = '%s' ", $mediaInventoryXml);
1114+
1115 // Restrict to the display license
1116 $SQL .= " WHERE license = '%s'";
1117 $SQL = sprintf($SQL, $time, $license);
1118@@ -284,31 +291,68 @@
1119 }
1120
1121 /**
1122- * Edits the default layout for a display
1123+ * Flags a display as being incomplete
1124 * @param <type> $displayId
1125- * @param <type> $defaultLayoutId
1126- * @return <type>
1127 */
1128- public function EditDefaultLayout($displayId, $defaultLayoutId)
1129+ private function FlagIncomplete($displayId)
1130 {
1131- $db =& $this->db;
1132-
1133- Debug::LogEntry($db, 'audit', 'IN', 'Display', 'EditDefaultLayout');
1134-
1135- $SQL = sprintf('UPDATE display SET defaultLayoutId = %d WHERE displayID = %d ', $defaultLayoutId, $displayId);
1136+ $db =& $this->db;
1137+
1138+ Debug::LogEntry($db, 'audit', sprintf('Flag DisplayID %d incomplete.', $displayId), 'display', 'NotifyDisplays');
1139+
1140+ $SQL = sprintf("UPDATE display SET MediaInventoryStatus = 3 WHERE displayID = %d", $displayId);
1141
1142 if (!$db->query($SQL))
1143 {
1144 trigger_error($db->error());
1145- $this->SetError(25012, __('Error updating this displays default layout.'));
1146-
1147- return false;
1148+ return $this->SetError(25004, 'Unable to Flag Display as incomplete');
1149 }
1150
1151-
1152- Debug::LogEntry($db, 'audit', 'OUT', 'Display', 'EditDefaultLayout');
1153-
1154 return true;
1155 }
1156+
1157+ /**
1158+ * Notify displays of this layout change
1159+ * @param <type> $layoutId
1160+ */
1161+ public function NotifyDisplays($layoutId)
1162+ {
1163+ $db =& $this->db;
1164+ $currentdate = time();
1165+ $rfLookahead = Kit::ValidateParam(Config::GetSetting($db,'REQUIRED_FILES_LOOKAHEAD'), _INT);
1166+
1167+ $rfLookahead = $currentdate + $rfLookahead;
1168+
1169+ Debug::LogEntry($db, 'audit', sprintf('Checking for Displays to refresh on Layout %d', $layoutId), 'display', 'NotifyDisplays');
1170+
1171+ // Which displays does a change to this layout effect?
1172+ $SQL = " SELECT DISTINCT display.DisplayID ";
1173+ $SQL .= " FROM schedule_detail ";
1174+ $SQL .= " INNER JOIN lkdisplaydg ";
1175+ $SQL .= " ON lkdisplaydg.DisplayGroupID = schedule_detail.DisplayGroupID ";
1176+ $SQL .= " INNER JOIN display ";
1177+ $SQL .= " ON lkdisplaydg.DisplayID = display.displayID ";
1178+ $SQL .= " WHERE schedule_detail.layoutID = %d ";
1179+ $SQL .= " AND schedule_detail.FromDT < %d AND schedule_detail.ToDT > %d ";
1180+ $SQL .= " UNION ";
1181+ $SQL .= " SELECT DisplayID FROM display WHERE DefaultLayoutID = %d";
1182+
1183+ $SQL = sprintf($SQL, $layoutId, $rfLookahead, $currentdate - 3600, $layoutId);
1184+
1185+ Debug::LogEntry($db, 'audit', $SQL, 'display', 'NotifyDisplays');
1186+
1187+ if (!$result = $db->query($SQL))
1188+ {
1189+ trigger_error($db->error());
1190+ return $this->SetError(25037, __('Unable to get layouts for Notify'));
1191+ }
1192+
1193+ while ($row = $db->get_assoc_row($result))
1194+ {
1195+ // Notify each display in turn
1196+ $displayId = Kit::ValidateParam($row['DisplayID'], _INT);
1197+ $this->FlagIncomplete($displayId);
1198+ }
1199+ }
1200 }
1201 ?>
1202
1203=== modified file 'server/lib/data/schedule.data.class.php'
1204--- server/lib/data/schedule.data.class.php 2011-02-10 19:46:44 +0000
1205+++ server/lib/data/schedule.data.class.php 2011-02-28 15:09:32 +0000
1206@@ -164,6 +164,11 @@
1207 }
1208 }
1209 }
1210+
1211+ // Notify (dont error)
1212+ Kit::ClassLoader('Display');
1213+ $displayObject = new Display($db);
1214+ $displayObject->NotifyDisplays($layoutID);
1215
1216 Debug::LogEntry($db, 'audit', 'OUT', 'Schedule', 'Add');
1217
1218
1219=== modified file 'server/lib/pages/display.class.php'
1220--- server/lib/pages/display.class.php 2011-02-13 17:16:01 +0000
1221+++ server/lib/pages/display.class.php 2011-02-28 15:09:32 +0000
1222@@ -37,6 +37,8 @@
1223 private $email_alert;
1224 private $alert_timeout;
1225 private $ajax;
1226+ private $mediaInventoryStatus;
1227+ private $mediaInventoryXml;
1228
1229 function __construct(database $db, user $user)
1230 {
1231@@ -71,7 +73,9 @@
1232 display.isAuditing,
1233 display.email_alert,
1234 display.alert_timeout,
1235- display.ClientAddress
1236+ display.ClientAddress,
1237+ display.MediaInventoryStatus,
1238+ display.MediaInventoryXml
1239 FROM display
1240 WHERE display.displayid = %d
1241 SQL;
1242@@ -95,8 +99,10 @@
1243 $this->licensed = Kit::ValidateParam($row[4], _INT);
1244 $this->inc_schedule = Kit::ValidateParam($row[5], _INT);
1245 $this->auditing = Kit::ValidateParam($row[6], _INT);
1246- $this->email_alert = Kit::ValidateParam($row[7], _INT);
1247- $this->alert_timeout = Kit::ValidateParam($row[8], _INT);
1248+ $this->email_alert = Kit::ValidateParam($row[7], _INT);
1249+ $this->alert_timeout = Kit::ValidateParam($row[8], _INT);
1250+ $this->mediaInventoryStatus = Kit::ValidateParam($row[9], _INT);
1251+ $this->mediaInventoryXml = Kit::ValidateParam($row[10], _HTMLSTRING);
1252 }
1253 }
1254
1255@@ -309,7 +315,12 @@
1256 CASE WHEN display.licensed = 1 THEN '<img src="img/act.gif">' ELSE '<img src="img/disact.gif">' END AS licensed,
1257 CASE WHEN display.email_alert = 1 THEN '<img src="img/act.gif">' ELSE '<img src="img/disact.gif">' END AS email_alert,
1258 displaygroup.DisplayGroupID,
1259- display.ClientAddress
1260+ display.ClientAddress,
1261+ CASE WHEN display.MediaInventoryStatus = 1 THEN '<img src="img/act.gif">'
1262+ WHEN display.MediaInventoryStatus = 2 THEN '<img src="img/warn.gif">'
1263+ ELSE '<img src="img/disact.gif">'
1264+ END AS MediaInventoryStatus,
1265+ display.MediaInventoryXml
1266 FROM display
1267 INNER JOIN lkdisplaydg ON lkdisplaydg.DisplayID = display.DisplayID
1268 INNER JOIN displaygroup ON displaygroup.DisplayGroupID = lkdisplaydg.DisplayGroupID
1269@@ -341,6 +352,8 @@
1270 $msgGroupSecurity = __('Group Security');
1271 $msgClientAddress = __('IP Address');
1272 $msgDefault = __('Default Layout');
1273+ $msgStatus = __('Status');
1274+ $msgMediaInventory = __('Media Inventory');
1275
1276 $output = <<<END
1277 <div class="info_table">
1278@@ -356,6 +369,7 @@
1279 <th>$msgLogIn</th>
1280 <th>$msgLastA</th>
1281 <th>$msgClientAddress</th>
1282+ <th>$msgStatus</th>
1283 <th>$msgAction</th>
1284 </tr>
1285 </thead>
1286@@ -385,6 +399,7 @@
1287 // Do we want to make a VNC link out of the display name?
1288 $vncTemplate = Config::GetSetting($db, 'SHOW_DISPLAY_AS_VNCLINK');
1289 $linkTarget = Kit::ValidateParam(Config::GetSetting($db, 'SHOW_DISPLAY_AS_VNC_TGT'), _STRING);
1290+ $mediaInventoryStatusLight = Kit::ValidateParam($aRow[10], _STRING);
1291
1292 if ($vncTemplate != '' && $clientAddress != '')
1293 {
1294@@ -424,6 +439,7 @@
1295 <td>$loggedin</td>
1296 <td>$lastaccessed</td>
1297 <td>$clientAddress</td>
1298+ <td>$mediaInventoryStatusLight</td>
1299 <td>$buttons</td>
1300 END;
1301 }
1302@@ -720,5 +736,59 @@
1303 $response->SetFormSubmitResponse(__('Display Saved.'));
1304 $response->Respond();
1305 }
1306+
1307+ /**
1308+ * Shows the inventory XML for the display
1309+ */
1310+ public function MediaInventory()
1311+ {
1312+ $db =& $this->db;
1313+ $response = new ResponseManager();
1314+ $displayId = Kit::GetParam('DisplayId', _GET, _INT);
1315+
1316+ if ($displayId == 0)
1317+ trigger_error(__('No DisplayId Given'));
1318+
1319+ // Get the media inventory xml for this display
1320+ $SQL = "SELECT MediaInventoryXml FROM display WHERE DisplayId = %d";
1321+ $SQL = sprintf($SQL, $displayId);
1322+
1323+ if (!$mediaInventoryXml = $db->GetSingleValue($SQL, 'MediaInventoryXml', _HTMLSTRING))
1324+ {
1325+ trigger_error($db->error());
1326+ trigger_error(__('Unable to get the Inventory for this Display'), E_USER_ERROR);
1327+ }
1328+
1329+ // Load the XML into a DOMDocument
1330+ $document = new DOMDocument("1.0");
1331+
1332+ if (!$document->loadXML($mediaInventoryXml))
1333+ trigger_error(__('Invalid Media Inventory'), E_USER_ERROR);
1334+
1335+ // Output a table
1336+ $table = '<table><tr><th>Type</th><th>Id</th><th>Complete</th><th>Last Checked</th><th>MD5</th></tr>';
1337+
1338+ foreach ($document->documentElement->childNodes as $node)
1339+ {
1340+ $type = $node->getAttribute('type');
1341+ $id = $node->getAttribute('id');
1342+ $complete = $node->getAttribute('complete');
1343+ $lastChecked = $node->getAttribute('lastChecked');
1344+ $md5 = $node->getAttribute('md5');
1345+
1346+ if ($complete == 0)
1347+ $complete = __('No');
1348+ else
1349+ $complete = __('Yes');
1350+
1351+ $table .= sprintf('<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td>', $type, $id, $complete, $lastChecked, $md5);
1352+ }
1353+
1354+ $table .= '</table>';
1355+
1356+ $response->SetFormRequestResponse($table, __('Media Inventory'), '550px', '350px');
1357+ $response->AddButton(__('Close'), 'XiboDialogClose()');
1358+ $response->Respond();
1359+ }
1360 }
1361 ?>
1362
1363=== modified file 'server/lib/pages/layout.class.php'
1364--- server/lib/pages/layout.class.php 2011-02-10 21:01:27 +0000
1365+++ server/lib/pages/layout.class.php 2011-02-28 15:09:32 +0000
1366@@ -427,6 +427,12 @@
1367 trigger_error($layoutObject->GetErrorMessage(), E_USER_ERROR);
1368 }
1369
1370+ // Notify (dont error)
1371+ Kit::ClassLoader('display');
1372+ $displayObject = new Display($db);
1373+ $displayObject->NotifyDisplays($this->layoutid);
1374+
1375+
1376 $response->SetFormSubmitResponse(__('Layout Details Changed.'));
1377 $response->Respond();
1378 }
1379
1380=== modified file 'server/lib/pages/region.class.php'
1381--- server/lib/pages/region.class.php 2010-05-29 11:16:24 +0000
1382+++ server/lib/pages/region.class.php 2011-02-28 15:09:32 +0000
1383@@ -76,6 +76,11 @@
1384 $this->errMsg = __("Unable to Update that layouts XML with a new Media Node");
1385 return false;
1386 }
1387+
1388+ // Notify (dont error)
1389+ Kit::ClassLoader('display');
1390+ $displayObject = new Display($db);
1391+ $displayObject->NotifyDisplays($layoutid);
1392
1393 return true;
1394 }
1395
1396=== modified file 'server/lib/service/service.wsdl'
1397--- server/lib/service/service.wsdl 2010-01-31 00:38:32 +0000
1398+++ server/lib/service/service.wsdl 2011-02-28 15:09:32 +0000
1399@@ -80,6 +80,15 @@
1400 <message name="SubmitStatsResponse">
1401 <part name="success" type="xsd:boolean" />
1402 </message>
1403+ <message name="MediaInventoryRequest">
1404+ <part name="version" type="xsd:string" />
1405+ <part name="serverKey" type="xsd:string" />
1406+ <part name="hardwareKey" type="xsd:string" />
1407+ <part name="mediaInventory" type="xsd:string" />
1408+ </message>
1409+ <message name="MediaInventoryResponse">
1410+ <part name="success" type="xsd:boolean" />
1411+ </message>
1412 <portType name="xmdsPortType">
1413 <operation name="RegisterDisplay">
1414 <documentation>Registered the Display on the Xibo Network</documentation>
1415@@ -121,6 +130,11 @@
1416 <input message="tns:SubmitStatsRequest"/>
1417 <output message="tns:SubmitStatsResponse"/>
1418 </operation>
1419+ <operation name="MediaInventory">
1420+ <documentation>Report back the clients MediaInventory</documentation>
1421+ <input message="tns:MediaInventoryRequest" />
1422+ <output message="tns:MediaInventoryResponse" />
1423+ </operation>
1424 </portType>
1425 <binding name="xmdsBinding" type="tns:xmdsPortType">
1426 <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
1427@@ -196,6 +210,15 @@
1428 <soap:body use="encoded" namespace="urn:xmds" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
1429 </output>
1430 </operation>
1431+ <operation name="MediaInventory">
1432+ <soap:operation soapAction="urn:xmds#MediaInventory" style="rpc"/>
1433+ <input>
1434+ <soap:body use="encoded" namespace="urn:xmds" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
1435+ </input>
1436+ <output>
1437+ <soap:body use="encoded" namespace="urn:xmds" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
1438+ </output>
1439+ </operation>
1440 </binding>
1441 <service name="xmds">
1442 <port name="xmdsPort" binding="tns:xmdsBinding">
1443
1444=== modified file 'server/lib/service/xmdssoap.class.php'
1445--- server/lib/service/xmdssoap.class.php 2011-02-07 16:46:09 +0000
1446+++ server/lib/service/xmdssoap.class.php 2011-02-28 15:09:32 +0000
1447@@ -848,6 +848,66 @@
1448 }
1449
1450 /**
1451+ * Store the media inventory for a client
1452+ * @param <type> $hardwareKey
1453+ * @param <type> $inventory
1454+ */
1455+ public function MediaInventory($version, $serverKey, $hardwareKey, $inventory)
1456+ {
1457+ $db =& $this->db;
1458+
1459+ // Sanitize
1460+ $serverKey = Kit::ValidateParam($serverKey, _STRING);
1461+ $hardwareKey = Kit::ValidateParam($hardwareKey, _STRING);
1462+ $version = Kit::ValidateParam($version, _STRING);
1463+ $inventory = Kit::ValidateParam($inventory, _HTMLSTRING);
1464+
1465+ // Make sure we are talking the same language
1466+ if (!$this->CheckVersion($version))
1467+ throw new SoapFault('Receiver', "Your client is not of the correct version for communication with this server. You can get the latest from http://www.xibo.org.uk");
1468+
1469+ // Auth this request...
1470+ if (!$this->AuthDisplay($hardwareKey))
1471+ throw new SoapFault('Receiver', 'This display client is not licensed');
1472+
1473+ if ($this->isAuditing == 1) Debug::LogEntry ($db, 'audit', $inventory, 'xmds', 'MediaInventory', '', $this->displayId);
1474+
1475+ // Check that the $inventory contains something
1476+ if ($inventory == '')
1477+ throw new SoapFault('Receiver', 'Inventory Cannot be Empty');
1478+
1479+ // Load the XML into a DOMDocument
1480+ $document = new DOMDocument("1.0");
1481+ $document->loadXML($inventory);
1482+
1483+ // Assume we are complete (but we are getting some)
1484+ $mediaInventoryComplete = 1;
1485+
1486+ foreach ($document->documentElement->childNodes as $node)
1487+ {
1488+ // Make sure we dont consider any text nodes
1489+ if ($node->nodeType == XML_TEXT_NODE) continue;
1490+
1491+ $mediaId = $node->getAttribute('id');
1492+ $complete = $node->getAttribute('complete');
1493+ $md5 = $node->getAttribute('md5');
1494+ $lastChecked = $node->getAttribute('lastChecked');
1495+
1496+ // Check the MD5?
1497+
1498+ // If this item is a 0 then set not complete
1499+ if ($complete == 0)
1500+ $mediaInventoryComplete = 2;
1501+ }
1502+
1503+ // Touch the display record
1504+ $displayObject = new Display($db);
1505+ $displayObject->Touch($hardwareKey, '', $mediaInventoryComplete, $inventory);
1506+
1507+ return true;
1508+ }
1509+
1510+ /**
1511 * Authenticates the display
1512 * @param <type> $hardwareKey
1513 * @return <type>

Subscribers

People subscribed via source and target branches