]> git.sesse.net Git - casparcg/blob - protocol/amcp/AMCPCommandsImpl.cpp
2.0.0.2: AMCP: CLEAR without layer clears entire channel.
[casparcg] / protocol / amcp / AMCPCommandsImpl.cpp
1 /*\r
2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 *  This file is part of CasparCG.\r
5 *\r
6 *    CasparCG is free software: you can redistribute it and/or modify\r
7 *    it under the terms of the GNU General Public License as published by\r
8 *    the Free Software Foundation, either version 3 of the License, or\r
9 *    (at your option) any later version.\r
10 *\r
11 *    CasparCG is distributed in the hope that it will be useful,\r
12 *    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 *    GNU General Public License for more details.\r
15 \r
16 *    You should have received a copy of the GNU General Public License\r
17 *    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
18 *\r
19 */\r
20 \r
21 #include "../StdAfx.h"\r
22 \r
23 #include "AMCPCommandsImpl.h"\r
24 #include "AMCPProtocolStrategy.h"\r
25 #include "../media.h"\r
26 \r
27 #include <core/producer/frame_producer.h>\r
28 #include <core/video_format.h>\r
29 #include <core/producer/flash/flash_producer.h>\r
30 #include <core/producer/transition/transition_producer.h>\r
31 #include <core/producer/flash/cg_producer.h>\r
32 \r
33 #include <common/env.h>\r
34 \r
35 #include <algorithm>\r
36 #include <locale>\r
37 #include <fstream>\r
38 #include <cctype>\r
39 #include <io.h>\r
40 \r
41 #include <boost/date_time/posix_time/posix_time.hpp>\r
42 #include <boost/lexical_cast.hpp>\r
43 #include <boost/algorithm/string.hpp>\r
44 #include <boost/filesystem.hpp>\r
45 \r
46 #if defined(_MSC_VER)\r
47 #pragma warning (push, 1) // TODO: Legacy code, just disable warnings\r
48 #endif\r
49 \r
50 /* Return codes\r
51 \r
52 100 [action]                    Information om att något har hänt  \r
53 101 [action]                    Information om att något har hänt, en rad data skickas  \r
54 \r
55 202 [kommando] OK               Kommandot har utförts  \r
56 201 [kommando] OK               Kommandot har utförts, och en rad data skickas tillbaka  \r
57 200 [kommando] OK               Kommandot har utförts, och flera rader data skickas tillbaka. Avslutas med tomrad  \r
58 \r
59 400 ERROR                               Kommandot kunde inte förstås  \r
60 401 [kommando] ERROR    Ogiltig kanal  \r
61 402 [kommando] ERROR    Parameter saknas  \r
62 403 [kommando] ERROR    Ogiltig parameter  \r
63 404 [kommando] ERROR    Mediafilen hittades inte  \r
64 \r
65 500 FAILED                              Internt configurationfel  \r
66 501 [kommando] FAILED   Internt configurationfel  \r
67 502 [kommando] FAILED   Oläslig mediafil  \r
68 \r
69 600 [kommando] FAILED   funktion ej implementerad\r
70 */\r
71 \r
72 namespace caspar { namespace protocol {\r
73 \r
74 using namespace core;\r
75 \r
76 std::wstring ListMedia()\r
77 {       \r
78         std::wstringstream replyString;\r
79         for (boost::filesystem::wrecursive_directory_iterator itr(env::media_folder()), end; itr != end; ++itr)\r
80         {                       \r
81                 if(boost::filesystem::is_regular_file(itr->path()))\r
82                 {\r
83                         std::wstring clipttype = TEXT(" N/A ");\r
84                         std::wstring extension = boost::to_upper_copy(itr->path().extension());\r
85                         if(extension == TEXT(".TGA") || extension == TEXT(".COL"))\r
86                                 clipttype = TEXT(" STILL ");\r
87                         else if(extension == TEXT(".SWF") || extension == TEXT(".DV") || extension == TEXT(".MOV") || extension == TEXT(".MPG") || \r
88                                         extension == TEXT(".AVI") || extension == TEXT(".FLV") || extension == TEXT(".F4V") || extension == TEXT(".MP4"))\r
89                                 clipttype = TEXT(" MOVIE ");\r
90                         else if(extension == TEXT(".WAV") || extension == TEXT(".MP3"))\r
91                                 clipttype = TEXT(" STILL ");\r
92 \r
93                         if(clipttype != TEXT(" N/A "))\r
94                         {               \r
95                                 auto is_not_digit = [](char c){ return std::isdigit(c) == 0; };\r
96 \r
97                                 auto relativePath = boost::filesystem::wpath(itr->path().file_string().substr(env::media_folder().size()-1, itr->path().file_string().size()));\r
98 \r
99                                 auto writeTimeStr = boost::posix_time::to_iso_string(boost::posix_time::from_time_t(boost::filesystem::last_write_time(itr->path())));\r
100                                 writeTimeStr.erase(std::remove_if(writeTimeStr.begin(), writeTimeStr.end(), is_not_digit), writeTimeStr.end());\r
101                                 auto writeTimeWStr = std::wstring(writeTimeStr.begin(), writeTimeStr.end());\r
102 \r
103                                 auto sizeStr = boost::lexical_cast<std::wstring>(boost::filesystem::file_size(itr->path()));\r
104                                 sizeStr.erase(std::remove_if(sizeStr.begin(), sizeStr.end(), is_not_digit), sizeStr.end());\r
105                                 auto sizeWStr = std::wstring(sizeStr.begin(), sizeStr.end());\r
106 \r
107                                 replyString << TEXT("\"") << relativePath.replace_extension(TEXT(""))\r
108                                                         << TEXT("\" ") << clipttype \r
109                                                         << TEXT(" ") << sizeStr\r
110                                                         << TEXT(" ") << writeTimeWStr\r
111                                                         << TEXT("\r\n");\r
112                         }       \r
113                 }\r
114         }\r
115         return boost::to_upper_copy(replyString.str());\r
116 }\r
117 \r
118 std::wstring ListTemplates() \r
119 {\r
120         std::wstringstream replyString;\r
121 \r
122         for (boost::filesystem::wrecursive_directory_iterator itr(env::template_folder()), end; itr != end; ++itr)\r
123         {               \r
124                 if(boost::filesystem::is_regular_file(itr->path()) && itr->path().extension() == L".ft")\r
125                 {\r
126                         auto relativePath = boost::filesystem::wpath(itr->path().file_string().substr(env::template_folder().size()-1, itr->path().file_string().size()));\r
127 \r
128                         auto writeTimeStr = boost::posix_time::to_iso_string(boost::posix_time::from_time_t(boost::filesystem::last_write_time(itr->path())));\r
129                         writeTimeStr.erase(std::remove_if(writeTimeStr.begin(), writeTimeStr.end(), [](char c){ return std::isdigit(c) == 0;}), writeTimeStr.end());\r
130                         auto writeTimeWStr = std::wstring(writeTimeStr.begin(), writeTimeStr.end());\r
131 \r
132                         auto sizeStr = boost::lexical_cast<std::string>(boost::filesystem::file_size(itr->path()));\r
133                         sizeStr.erase(std::remove_if(sizeStr.begin(), sizeStr.end(), [](char c){ return std::isdigit(c) == 0;}), sizeStr.end());\r
134 \r
135                         auto sizeWStr = std::wstring(sizeStr.begin(), sizeStr.end());\r
136                         \r
137                         replyString << TEXT("\"") << relativePath.replace_extension(TEXT(""))\r
138                                                 << TEXT("\" ") << sizeWStr\r
139                                                 << TEXT(" ") << writeTimeWStr\r
140                                                 << TEXT("\r\n");                \r
141                 }\r
142         }\r
143         return boost::to_upper_copy(replyString.str());\r
144 }\r
145 \r
146 namespace amcp {\r
147         \r
148 AMCPCommand::AMCPCommand() : channelIndex_(0), scheduling_(Default), layerIndex_(-1)\r
149 {}\r
150 \r
151 void AMCPCommand::SendReply()\r
152 {\r
153         if(!pClientInfo_) \r
154                 return;\r
155 \r
156         if(replyString_.empty())\r
157                 return;\r
158         pClientInfo_->Send(replyString_);\r
159 }\r
160 \r
161 void AMCPCommand::Clear() \r
162 {\r
163         pChannel_->clear();\r
164         pClientInfo_.reset();\r
165         channelIndex_ = 0;\r
166         _parameters.clear();\r
167 }\r
168 \r
169 bool LoadCommand::DoExecute()\r
170 {       \r
171         //Perform loading of the clip\r
172         try\r
173         {\r
174                 _parameters[0] = _parameters[0];\r
175                 auto pFP = load_media(_parameters);             \r
176                 GetChannel()->preview(GetLayerIndex(), pFP);\r
177         \r
178                 CASPAR_LOG(info) << "Loaded " <<  _parameters[0] << TEXT(" successfully");\r
179 \r
180                 SetReplyString(TEXT("202 LOAD OK\r\n"));\r
181 \r
182                 return true;\r
183         }\r
184         catch(file_not_found&)\r
185         {\r
186                 CASPAR_LOG_CURRENT_EXCEPTION();\r
187                 SetReplyString(TEXT("404 LOADBG ERROR\r\n"));\r
188                 return false;\r
189         }\r
190         catch(...)\r
191         {\r
192                 CASPAR_LOG_CURRENT_EXCEPTION();\r
193                 SetReplyString(TEXT("502 LOADBG FAILED\r\n"));\r
194                 return false;\r
195         }\r
196 }\r
197 \r
198 bool LoadbgCommand::DoExecute()\r
199 {\r
200         transition_info transitionInfo;\r
201         \r
202         bool bLoop = false;\r
203         unsigned short transitionParameterIndex = 1;\r
204 \r
205         if(_parameters.size() > 1 && _parameters[1] == TEXT("LOOP"))\r
206                 ++transitionParameterIndex;\r
207 \r
208         //Setup transition info\r
209         if(_parameters.size() > transitionParameterIndex)       //type\r
210         {\r
211                 std::wstring transitionType = _parameters[transitionParameterIndex];\r
212 \r
213                 if(transitionType == TEXT("CUT"))\r
214                         transitionInfo.type = transition::cut;\r
215                 else if(transitionType == TEXT("MIX"))\r
216                         transitionInfo.type = transition::mix;\r
217                 else if(transitionType == TEXT("PUSH"))\r
218                         transitionInfo.type = transition::push;\r
219                 else if(transitionType == TEXT("SLIDE"))\r
220                         transitionInfo.type = transition::slide;\r
221                 else if(transitionType == TEXT("WIPE"))\r
222                         transitionInfo.type = transition::wipe;\r
223 \r
224                 if(_parameters.size() > static_cast<unsigned short>(transitionParameterIndex+1))        //duration\r
225                 {\r
226                         int duration = _ttoi(_parameters[transitionParameterIndex+1].c_str());\r
227                         if(duration > 0)\r
228                                 transitionInfo.duration = duration;\r
229 \r
230                         if(_parameters.size() > static_cast<unsigned short>(transitionParameterIndex+2))        //direction\r
231                         {\r
232                                 std::wstring direction = _parameters[transitionParameterIndex+2];\r
233 \r
234                                 if(direction == TEXT("FROMLEFT"))\r
235                                         transitionInfo.direction = transition_direction::from_left;\r
236                                 else if(direction == TEXT("FROMRIGHT"))\r
237                                         transitionInfo.direction = transition_direction::from_right;\r
238                                 else if(direction == TEXT("LEFT"))\r
239                                         transitionInfo.direction = transition_direction::from_right;\r
240                                 else if(direction == TEXT("RIGHT"))\r
241                                         transitionInfo.direction = transition_direction::from_left;\r
242                         }\r
243                 }\r
244         }\r
245 \r
246         //Perform loading of the clip\r
247         try\r
248         {\r
249                 _parameters[0] = _parameters[0];\r
250                 auto pFP = load_media(_parameters);\r
251                 if(pFP == frame_producer::empty())\r
252                         BOOST_THROW_EXCEPTION(file_not_found() << msg_info(_parameters.size() > 0 ? narrow(_parameters[0]) : ""));\r
253 \r
254                 pFP = safe_ptr<core::frame_producer>(transition_producer(pFP, transitionInfo));\r
255                 bool autoPlay = std::find(_parameters.begin(), _parameters.end(), TEXT("AUTOPLAY")) != _parameters.end();\r
256                 GetChannel()->load(GetLayerIndex(), pFP, autoPlay); // TODO: LOOP\r
257         \r
258                 CASPAR_LOG(info) << "Loaded " << _parameters[0] << TEXT(" successfully to background");\r
259                 SetReplyString(TEXT("202 LOADBG OK\r\n"));\r
260 \r
261                 return true;\r
262         }\r
263         catch(file_not_found&)\r
264         {\r
265                 CASPAR_LOG_CURRENT_EXCEPTION();\r
266                 SetReplyString(TEXT("404 LOADBG ERROR\r\n"));\r
267                 return false;\r
268         }\r
269         catch(...)\r
270         {\r
271                 CASPAR_LOG_CURRENT_EXCEPTION();\r
272                 SetReplyString(TEXT("502 LOADBG FAILED\r\n"));\r
273                 return false;\r
274         }\r
275 }\r
276 \r
277 bool PauseCommand::DoExecute()\r
278 {\r
279         try\r
280         {\r
281                 GetChannel()->pause(GetLayerIndex());\r
282                 SetReplyString(TEXT("202 PAUSE OK\r\n"));\r
283                 return true;\r
284         }\r
285         catch(...)\r
286         {\r
287                 SetReplyString(TEXT("501 PAUSE FAILED\r\n"));\r
288         }\r
289 \r
290         return false;\r
291 }\r
292 \r
293 bool PlayCommand::DoExecute()\r
294 {\r
295         try\r
296         {\r
297                 GetChannel()->play(GetLayerIndex());\r
298                 SetReplyString(TEXT("202 PLAY OK\r\n"));\r
299                 return true;\r
300         }\r
301         catch(...)\r
302         {\r
303                 SetReplyString(TEXT("501 PLAY FAILED\r\n"));\r
304         }\r
305 \r
306         return false;\r
307 }\r
308 \r
309 bool StopCommand::DoExecute()\r
310 {\r
311         try\r
312         {\r
313                 GetChannel()->stop(GetLayerIndex());\r
314                 SetReplyString(TEXT("202 STOP OK\r\n"));\r
315                 return true;\r
316         }\r
317         catch(...)\r
318         {\r
319                 SetReplyString(TEXT("501 STOP FAILED\r\n"));\r
320         }\r
321 \r
322         return false;\r
323 }\r
324 \r
325 bool ClearCommand::DoExecute()\r
326 {\r
327         int index = GetLayerIndex(std::numeric_limits<int>::max());\r
328         if(index == std::numeric_limits<int>::max())\r
329                 GetChannel()->clear();\r
330         else\r
331                 GetChannel()->clear(index);\r
332                 \r
333         SetReplyString(TEXT("202 CLEAR OK\r\n"));\r
334 \r
335         return true;\r
336 }\r
337 \r
338 bool CGCommand::DoExecute()\r
339 {\r
340         std::wstring command = _parameters[0];\r
341         if(command == TEXT("ADD"))\r
342                 return DoExecuteAdd();\r
343         else if(command == TEXT("PLAY"))\r
344                 return DoExecutePlay();\r
345         else if(command == TEXT("STOP"))\r
346                 return DoExecuteStop();\r
347         else if(command == TEXT("NEXT"))\r
348                 return DoExecuteNext();\r
349         else if(command == TEXT("REMOVE"))\r
350                 return DoExecuteRemove();\r
351         else if(command == TEXT("CLEAR"))\r
352                 return DoExecuteClear();\r
353         else if(command == TEXT("UPDATE"))\r
354                 return DoExecuteUpdate();\r
355         else if(command == TEXT("INVOKE"))\r
356                 return DoExecuteInvoke();\r
357         else if(command == TEXT("INFO"))\r
358                 return DoExecuteInfo();\r
359 \r
360         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
361         return false;\r
362 }\r
363 \r
364 bool CGCommand::ValidateLayer(const std::wstring& layerstring) {\r
365         int length = layerstring.length();\r
366         for(int i = 0; i < length; ++i) {\r
367                 if(!_istdigit(layerstring[i])) {\r
368                         return false;\r
369                 }\r
370         }\r
371 \r
372         return true;\r
373 }\r
374 \r
375 bool CGCommand::DoExecuteAdd() {\r
376         //CG 1 ADD 0 "template_folder/templatename" [STARTLABEL] 0/1 [DATA]\r
377 \r
378         int layer = 0;                          //_parameters[1]\r
379 //      std::wstring templateName;      //_parameters[2]\r
380         std::wstring label;             //_parameters[3]\r
381         bool bDoStart = false;          //_parameters[3] alt. _parameters[4]\r
382 //      std::wstring data;                      //_parameters[4] alt. _parameters[5]\r
383 \r
384         if(_parameters.size() < 4) \r
385         {\r
386                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
387                 return false;\r
388         }\r
389         unsigned int dataIndex = 4;\r
390 \r
391         if(!ValidateLayer(_parameters[1])) \r
392         {\r
393                 SetReplyString(TEXT("403 CG ERROR\r\n"));\r
394                 return false;\r
395         }\r
396 \r
397         layer = _ttoi(_parameters[1].c_str());\r
398 \r
399         if(_parameters[3].length() > 1) \r
400         {       //read label\r
401                 label = _parameters[3];\r
402                 ++dataIndex;\r
403 \r
404                 if(_parameters.size() > 4 && _parameters[4].length() > 0)       //read play-on-load-flag\r
405                         bDoStart = (_parameters[4][0]==TEXT('1')) ? true : false;\r
406                 else \r
407                 {\r
408                         SetReplyString(TEXT("402 CG ERROR\r\n"));\r
409                         return false;\r
410                 }\r
411         }\r
412         else if(_parameters[3].length() > 0) {  //read play-on-load-flag\r
413                 bDoStart = (_parameters[3][0]==TEXT('1')) ? true : false;\r
414         }\r
415         else \r
416         {\r
417                 SetReplyString(TEXT("403 CG ERROR\r\n"));\r
418                 return false;\r
419         }\r
420 \r
421         const TCHAR* pDataString = 0;\r
422         std::wstringstream data;\r
423         std::wstring dataFromFile;\r
424         if(_parameters.size() > dataIndex) \r
425         {       //read data\r
426                 const std::wstring& dataString = _parameters[dataIndex];\r
427 \r
428                 if(dataString[0] == TEXT('<')) //the data is an XML-string\r
429                         pDataString = dataString.c_str();\r
430                 else \r
431                 {\r
432                         //The data is not an XML-string, it must be a filename\r
433                         std::wstring filename = env::data_folder();\r
434                         filename.append(dataString);\r
435                         filename.append(TEXT(".ftd"));\r
436 \r
437                         //open file\r
438                         std::wifstream datafile(filename.c_str());\r
439                         if(datafile) \r
440                         {\r
441                                 //read all data\r
442                                 data << datafile.rdbuf();\r
443                                 datafile.close();\r
444 \r
445                                 //extract data to _parameters\r
446                                 dataFromFile = data.str();\r
447                                 pDataString = dataFromFile.c_str();\r
448                         }\r
449                 }\r
450         }\r
451 \r
452         std::wstring fullFilename = core::flash::flash_producer::find_template(env::template_folder() + _parameters[2]);\r
453         if(!fullFilename.empty())\r
454         {\r
455                 std::wstring extension = boost::filesystem::wpath(fullFilename).extension();\r
456                 std::wstring filename = _parameters[2];\r
457                 filename.append(extension);\r
458 \r
459                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->add(layer, filename, bDoStart, label, (pDataString!=0) ? pDataString : TEXT(""));\r
460                 SetReplyString(TEXT("202 CG OK\r\n"));\r
461         }\r
462         else\r
463         {\r
464                 CASPAR_LOG(warning) << "Could not find template " << _parameters[2];\r
465                 SetReplyString(TEXT("404 CG ERROR\r\n"));\r
466         }\r
467         return true;\r
468 }\r
469 \r
470 bool CGCommand::DoExecutePlay()\r
471 {\r
472         if(_parameters.size() > 1)\r
473         {\r
474                 if(!ValidateLayer(_parameters[1])) \r
475                 {\r
476                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
477                         return false;\r
478                 }\r
479                 int layer = _ttoi(_parameters[1].c_str());\r
480                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->play(layer);\r
481         }\r
482         else\r
483         {\r
484                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
485                 return true;\r
486         }\r
487 \r
488         SetReplyString(TEXT("202 CG OK\r\n"));\r
489         return true;\r
490 }\r
491 \r
492 bool CGCommand::DoExecuteStop() \r
493 {\r
494         if(_parameters.size() > 1)\r
495         {\r
496                 if(!ValidateLayer(_parameters[1])) \r
497                 {\r
498                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
499                         return false;\r
500                 }\r
501                 int layer = _ttoi(_parameters[1].c_str());\r
502                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->stop(layer, 0);\r
503         }\r
504         else \r
505         {\r
506                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
507                 return true;\r
508         }\r
509 \r
510         SetReplyString(TEXT("202 CG OK\r\n"));\r
511         return true;\r
512 }\r
513 \r
514 bool CGCommand::DoExecuteNext()\r
515 {\r
516         if(_parameters.size() > 1) \r
517         {\r
518                 if(!ValidateLayer(_parameters[1])) \r
519                 {\r
520                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
521                         return false;\r
522                 }\r
523                 int layer = _ttoi(_parameters[1].c_str());\r
524                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->next(layer);\r
525         }\r
526         else \r
527         {\r
528                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
529                 return true;\r
530         }\r
531 \r
532         SetReplyString(TEXT("202 CG OK\r\n"));\r
533         return true;\r
534 }\r
535 \r
536 bool CGCommand::DoExecuteRemove() \r
537 {\r
538         if(_parameters.size() > 1) \r
539         {\r
540                 if(!ValidateLayer(_parameters[1])) \r
541                 {\r
542                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
543                         return false;\r
544                 }\r
545                 int layer = _ttoi(_parameters[1].c_str());\r
546                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->remove(layer);\r
547         }\r
548         else \r
549         {\r
550                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
551                 return true;\r
552         }\r
553 \r
554         SetReplyString(TEXT("202 CG OK\r\n"));\r
555         return true;\r
556 }\r
557 \r
558 bool CGCommand::DoExecuteClear() \r
559 {\r
560         core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->clear();\r
561         SetReplyString(TEXT("202 CG OK\r\n"));\r
562         return true;\r
563 }\r
564 \r
565 bool CGCommand::DoExecuteUpdate() \r
566 {\r
567         if(_parameters.size() > 2) \r
568         {\r
569                 if(!ValidateLayer(_parameters[1]))\r
570                 {\r
571                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
572                         return false;\r
573                 }\r
574                 int layer = _ttoi(_parameters[1].c_str());\r
575                 //TODO: Implement indirect data loading from file. Same as in Add\r
576                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->update(layer, _parameters[2]);\r
577         }\r
578         else \r
579         {\r
580                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
581                 return true;\r
582         }\r
583 \r
584         SetReplyString(TEXT("202 CG OK\r\n"));\r
585         return true;\r
586 }\r
587 \r
588 bool CGCommand::DoExecuteInvoke() \r
589 {\r
590         if(_parameters.size() > 2)\r
591         {\r
592                 if(!ValidateLayer(_parameters[1]))\r
593                 {\r
594                         SetReplyString(TEXT("403 CG ERROR\r\n"));\r
595                         return false;\r
596                 }\r
597                 int layer = _ttoi(_parameters[1].c_str());\r
598                 core::flash::get_default_cg_producer(safe_ptr<core::channel>(GetChannel()), GetLayerIndex(core::flash::cg_producer::DEFAULT_LAYER))->invoke(layer, _parameters[2]);\r
599         }\r
600         else \r
601         {\r
602                 SetReplyString(TEXT("402 CG ERROR\r\n"));\r
603                 return true;\r
604         }\r
605 \r
606         SetReplyString(TEXT("202 CG OK\r\n"));\r
607         return true;\r
608 }\r
609 \r
610 bool CGCommand::DoExecuteInfo() \r
611 {\r
612         // TODO\r
613         //core::flash::get_default_cg_producer(GetChannel())->Info();\r
614         SetReplyString(TEXT("600 CG FAILED\r\n"));\r
615         return true;\r
616 }\r
617 \r
618 bool DataCommand::DoExecute()\r
619 {\r
620         std::wstring command = _parameters[0];\r
621         if(command == TEXT("STORE"))\r
622                 return DoExecuteStore();\r
623         else if(command == TEXT("RETRIEVE"))\r
624                 return DoExecuteRetrieve();\r
625         else if(command == TEXT("LIST"))\r
626                 return DoExecuteList();\r
627 \r
628         SetReplyString(TEXT("403 DATA ERROR\r\n"));\r
629         return false;\r
630 }\r
631 \r
632 bool DataCommand::DoExecuteStore() \r
633 {\r
634         if(_parameters.size() < 3) \r
635         {\r
636                 SetReplyString(TEXT("402 DATA STORE ERROR\r\n"));\r
637                 return false;\r
638         }\r
639 \r
640         std::wstring filename = env::data_folder();\r
641         filename.append(_parameters[1]);\r
642         filename.append(TEXT(".ftd"));\r
643 \r
644         std::wofstream datafile(filename.c_str());\r
645         if(!datafile) \r
646         {\r
647                 SetReplyString(TEXT("501 DATA STORE FAILED\r\n"));\r
648                 return false;\r
649         }\r
650 \r
651         datafile << _parameters[2];\r
652         datafile.close();\r
653 \r
654         std::wstring replyString = TEXT("202 DATA STORE OK\r\n");\r
655         SetReplyString(replyString);\r
656         return true;\r
657 }\r
658 \r
659 bool DataCommand::DoExecuteRetrieve() \r
660 {\r
661         if(_parameters.size() < 2) \r
662         {\r
663                 SetReplyString(TEXT("402 DATA RETRIEVE ERROR\r\n"));\r
664                 return false;\r
665         }\r
666 \r
667         std::wstring filename = env::data_folder();\r
668         filename.append(_parameters[1]);\r
669         filename.append(TEXT(".ftd"));\r
670 \r
671         std::wifstream datafile(filename.c_str());\r
672         if(!datafile) \r
673         {\r
674                 SetReplyString(TEXT("404 DATA RETRIEVE ERROR\r\n"));\r
675                 return false;\r
676         }\r
677 \r
678         std::wstringstream reply(TEXT("201 DATA RETRIEVE OK\r\n"));\r
679         std::wstring line;\r
680         bool bFirstLine = true;\r
681         while(std::getline(datafile, line))\r
682         {\r
683                 if(!bFirstLine)\r
684                         reply << "\\n";\r
685                 else\r
686                         bFirstLine = false;\r
687 \r
688                 reply << line;\r
689         }\r
690         datafile.close();\r
691 \r
692         reply << "\r\n";\r
693         SetReplyString(reply.str());\r
694         return true;\r
695 }\r
696 \r
697 bool DataCommand::DoExecuteList() \r
698 {\r
699         std::wstringstream replyString;\r
700         replyString << TEXT("200 DATA LIST OK\r\n");\r
701         replyString << ListMedia();\r
702         replyString << TEXT("\r\n");\r
703 \r
704         SetReplyString(boost::to_upper_copy(replyString.str()));\r
705         return true;\r
706 }\r
707 \r
708 bool CinfCommand::DoExecute()\r
709 {\r
710         std::wstringstream replyString;\r
711 \r
712         std::wstring filename = _parameters[0];\r
713 \r
714         // TODO:\r
715 \r
716         //FileInfo fileInfo;\r
717 \r
718         //MediaManagerPtr pMediaManager = GetApplication()->FindMediaFile(filename, &fileInfo);\r
719         //if(pMediaManager != 0 && fileInfo.filetype.length() >0)       //File was found\r
720         //{\r
721         //      if(pMediaManager->getFileInfo(&fileInfo))\r
722         //      {\r
723         //              TCHAR numBuffer[32];\r
724         //              _ui64tot_s(fileInfo.size, numBuffer, 32, 10);\r
725 \r
726         //              replyString << TEXT("201 CINF OK\r\n\"") << fileInfo.filename << TEXT("\" ") << fileInfo.type << TEXT("/") << fileInfo.filetype << TEXT("/") << fileInfo.encoding << TEXT(" ") << numBuffer << TEXT("\r\n");\r
727 \r
728         //              SetReplyString(replyString.str());\r
729         //              return true;\r
730         //      }\r
731         //}\r
732 \r
733         SetReplyString(TEXT("404 CINF ERROR\r\n"));\r
734         return false;\r
735 }\r
736 \r
737 void GenerateChannelInfo(int index, const safe_ptr<core::channel>& pChannel, std::wstringstream& replyString)\r
738 {\r
739         replyString << index << TEXT(" ") << pChannel->get_video_format_desc().name  << TEXT("\r\n") << (pChannel->foreground(0).get()->print());\r
740 }\r
741 \r
742 bool InfoCommand::DoExecute()\r
743 {\r
744         std::wstringstream replyString;\r
745 \r
746         if(_parameters.size() >= 1)\r
747         {\r
748                 int channelIndex = _ttoi(_parameters[0].c_str())-1;\r
749 \r
750                 if(channelIndex < channels_.size())\r
751                 {\r
752                         replyString << TEXT("201 INFO OK\r\n");\r
753                         GenerateChannelInfo(channelIndex, channels_[channelIndex], replyString);\r
754                 }\r
755                 else\r
756                 {\r
757                         SetReplyString(TEXT("401 INFO ERROR\r\n"));\r
758                         return false;\r
759                 }\r
760         }\r
761         else\r
762         {\r
763                 replyString << TEXT("200 INFO OK\r\n");\r
764                 for(size_t n = 0; n < channels_.size(); ++n)\r
765                         GenerateChannelInfo(n, channels_[n], replyString);\r
766                 replyString << TEXT("\r\n");\r
767         }\r
768 \r
769         SetReplyString(replyString.str());\r
770         return true;\r
771 }\r
772 \r
773 bool ClsCommand::DoExecute()\r
774 {\r
775 /*\r
776                 wav = audio\r
777                 mp3 = audio\r
778                 swf     = movie\r
779                 dv  = movie\r
780                 tga = still\r
781                 col = still\r
782         */\r
783         std::wstringstream replyString;\r
784         replyString << TEXT("200 CLS OK\r\n");\r
785         replyString << ListMedia();\r
786         replyString << TEXT("\r\n");\r
787         SetReplyString(boost::to_upper_copy(replyString.str()));\r
788         return true;\r
789 }\r
790 \r
791 bool TlsCommand::DoExecute()\r
792 {\r
793         std::wstringstream replyString;\r
794         replyString << TEXT("200 TLS OK\r\n");\r
795 \r
796         replyString << ListTemplates();\r
797         replyString << TEXT("\r\n");\r
798 \r
799         SetReplyString(replyString.str());\r
800         return true;\r
801 }\r
802 \r
803 bool VersionCommand::DoExecute()\r
804 {\r
805         std::wstringstream replyString;\r
806         replyString << TEXT("201 VERSION OK\r\n") << env::version() << TEXT("\r\n");\r
807 \r
808         SetReplyString(replyString.str());\r
809         return true;\r
810 }\r
811 \r
812 bool ByeCommand::DoExecute()\r
813 {\r
814         GetClientInfo()->Disconnect();\r
815         return true;\r
816 }\r
817 \r
818 bool SetCommand::DoExecute()\r
819 {\r
820         std::wstring name = _parameters[0];\r
821         std::transform(name.begin(), name.end(), name.begin(), toupper);\r
822 \r
823         std::wstring value = _parameters[1];\r
824         std::transform(value.begin(), value.end(), value.begin(), toupper);\r
825 \r
826         if(name == TEXT("MODE"))\r
827         {\r
828                 //if(this->GetChannel()->SetVideoFormat(value)) TODO\r
829                 //      this->SetReplyString(TEXT("202 SET MODE OK\r\n"));\r
830                 //else\r
831                         this->SetReplyString(TEXT("501 SET MODE FAILED\r\n"));\r
832         }\r
833         else\r
834         {\r
835                 this->SetReplyString(TEXT("403 SET ERROR\r\n"));\r
836         }\r
837 \r
838         return true;\r
839 }\r
840 \r
841 \r
842 }       //namespace amcp\r
843 }}      //namespace caspar