Merge branch 'master' into easysetup & CBOR changes
[platform/upstream/iotivity.git] / resource / csdk / stack / src / oicgroup.c
1 //******************************************************************
2 //
3 // Copyright 2014 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #define _POSIX_C_SOURCE 200112L
22
23 #include <string.h>
24
25 #include "oicgroup.h"
26 #include "cJSON.h"
27 #include "oic_malloc.h"
28 #include "oic_string.h"
29 #include "occollection.h"
30 #include "logger.h"
31 #include "timer.h"
32
33 #ifndef WITH_ARDUINO
34 #include <pthread.h>
35 #endif
36
37 #define TAG PCF("OICGROUP")
38
39 #define DESC_DELIMITER          "\""
40 #define ACTION_DELIMITER        "*"
41 #define ATTR_DELIMITER          "|"
42 #define ATTR_ASSIGN             "="
43
44 // Definitions for operations related to actions
45 #define DO_ACTION               "DoAction"
46 #define GET_ACTIONSET           "GetActionSet"
47 #define ACTIONSET               "ActionSet"
48 #define DELETE_ACTIONSET        "DelActionSet"
49
50 #define OIC_ACTION_PREFIX               "{\"oic\":[{\"rep\":{"
51 #define VARIFY_POINTER_NULL(pointer, result, toExit) \
52     if(pointer == NULL) \
53     {\
54         result = OC_STACK_NO_MEMORY;\
55         goto toExit;\
56     }
57 #define VARIFY_PARAM_NULL(pointer, result, toExit) \
58     if(pointer == NULL)\
59     {\
60         result = OC_STACK_INVALID_PARAM;\
61         goto exit;\
62     }
63
64 #define OCFREE(pointer) \
65     { \
66         OICFree(pointer); \
67         pointer = NULL; \
68     }
69
70 #ifndef WITH_ARDUINO
71 pthread_mutex_t lock;
72 #endif
73
74 enum ACTION_TYPE
75 {
76     NONE = 0, SCHEDULED, RECURSIVE
77 };
78
79 typedef struct scheduledresourceinfo
80 {
81     OCResource *resource;
82     OCActionSet *actionset;
83
84     int timer_id;
85
86     OCServerRequest *ehRequest;
87
88     time_t time;
89     struct scheduledresourceinfo* next;
90 } ScheduledResourceInfo;
91
92 ScheduledResourceInfo *scheduleResourceList = NULL;
93
94 void AddScheduledResource(ScheduledResourceInfo **head,
95         ScheduledResourceInfo* add)
96 {
97     OC_LOG(INFO, TAG, PCF("AddScheduledResource Entering..."));
98
99 #ifndef WITH_ARDUINO
100     pthread_mutex_lock(&lock);
101 #endif
102     ScheduledResourceInfo *tmp = NULL;
103
104     if (*head != NULL)
105     {
106         tmp = *head;
107
108         while (tmp->next)
109         {
110             tmp = tmp->next;
111         }
112         tmp->next = add;
113     }
114     else
115     {
116         *head = add;
117     }
118 #ifndef WITH_ARDUINO
119     pthread_mutex_unlock(&lock);
120 #endif
121 }
122
123 ScheduledResourceInfo* GetScheduledResource(ScheduledResourceInfo *head)
124 {
125     OC_LOG(INFO, TAG, PCF("GetScheduledResource Entering..."));
126
127 #ifndef WITH_ARDUINO
128     pthread_mutex_lock(&lock);
129 #endif
130
131     time_t t_now;
132
133     ScheduledResourceInfo *tmp = NULL;
134     tmp = head;
135
136 #ifndef WITH_ARDUINO
137     time(&t_now);
138 #else
139     t_now = now();
140 #endif
141
142     if (tmp)
143     {
144         while (tmp)
145         {
146             time_t diffTm = 0;
147 #ifndef WITH_ARDUINO
148             diffTm = timespec_diff(tmp->time, t_now);
149 #else
150             diffTm = timespec_diff(tmp->time, t_now);
151 #endif
152
153             if (diffTm <= (time_t) 0)
154             {
155                 OC_LOG(INFO, TAG, PCF("return Call INFO."));
156                 goto exit;
157             }
158
159             tmp = tmp->next;
160         }
161     }
162
163     exit:
164 #ifndef WITH_ARDUINO
165     pthread_mutex_unlock(&lock);
166 #endif
167     if (tmp == NULL)
168     {
169         OC_LOG(INFO, TAG, PCF("Cannot Find Call Info."));
170     }
171     return tmp;
172 }
173
174 ScheduledResourceInfo* GetScheduledResourceByActionSetName(ScheduledResourceInfo *head, char *setName)
175 {
176     OC_LOG(INFO, TAG, PCF("GetScheduledResourceByActionSetName Entering..."));
177
178 #ifndef WITH_ARDUINO
179     pthread_mutex_lock(&lock);
180 #endif
181     ScheduledResourceInfo *tmp = NULL;
182     tmp = head;
183
184     if (tmp)
185     {
186         while (tmp)
187         {
188             if (strcmp(tmp->actionset->actionsetName, setName) == 0)
189             {
190                 OC_LOG(INFO, TAG, PCF("return Call INFO."));
191                 goto exit;
192             }
193             tmp = tmp->next;
194         }
195     }
196
197 exit:
198 #ifndef WITH_ARDUINO
199     pthread_mutex_unlock(&lock);
200 #endif
201     if (tmp == NULL)
202     {
203         OC_LOG(INFO, TAG, PCF("Cannot Find Call Info."));
204     }
205     return tmp;
206 }
207
208 void RemoveScheduledResource(ScheduledResourceInfo **head,
209         ScheduledResourceInfo* del)
210 {
211 #ifndef WITH_ARDUINO
212     pthread_mutex_lock(&lock);
213 #endif
214     OC_LOG(INFO, TAG, PCF("RemoveScheduledResource Entering..."));
215     ScheduledResourceInfo *tmp = NULL;
216
217     if (del == NULL)
218     {
219         return;
220     }
221
222     if (*head == del)
223     {
224         *head = (*head)->next;
225     }
226     else
227     {
228         tmp = *head;
229         while (tmp->next && (tmp->next != del))
230         {
231             tmp = tmp->next;
232         }
233         if (tmp->next)
234         {
235             tmp->next = del->next;
236         }
237     }
238
239     OCFREE(del)
240 #ifndef WITH_ARDUINO
241     pthread_mutex_unlock(&lock);
242 #endif
243 }
244
245 typedef struct aggregatehandleinfo
246 {
247     OCServerRequest *ehRequest;
248     OCDoHandle required;
249     OCResource *collResource;
250
251     struct aggregatehandleinfo *next;
252 } ClientRequestInfo;
253
254 ClientRequestInfo *clientRequstList = NULL;
255
256 void AddClientRequestInfo(ClientRequestInfo **head, ClientRequestInfo* add)
257 {
258     ClientRequestInfo *tmp = NULL;
259
260     if (*head != NULL)
261     {
262         tmp = *head;
263
264         while (tmp->next)
265         {
266             tmp = tmp->next;
267         }
268         tmp->next = add;
269     }
270     else
271     {
272         *head = add;
273     }
274 }
275
276 ClientRequestInfo* GetClientRequestInfo(ClientRequestInfo *head,
277         OCDoHandle handle)
278 {
279     ClientRequestInfo *tmp = NULL;
280
281     tmp = head;
282
283     if (tmp)
284     {
285         while (tmp)
286         {
287             if (tmp->required == handle)
288             {
289                 break;
290             }
291
292             tmp = tmp->next;
293         }
294
295         return tmp;
296     }
297     return NULL;
298 }
299
300 void RemoveClientRequestInfo(ClientRequestInfo **head, ClientRequestInfo* del)
301 {
302     ClientRequestInfo *tmp = NULL;
303
304     if (del == NULL)
305         return;
306
307     if (*head == del)
308     {
309         *head = (*head)->next;
310     }
311     else
312     {
313         tmp = *head;
314         while (tmp->next && (tmp->next != del))
315         {
316             tmp = tmp->next;
317         }
318         if (tmp->next)
319         {
320             tmp->next = del->next;
321         }
322     }
323 }
324
325 void AddCapability(OCCapability** head, OCCapability* node)
326 {
327     OCCapability *pointer = *head;
328     if (NULL == pointer)
329     {
330         *head = node;
331     }
332     else
333     {
334         while (pointer->next != NULL)
335         {
336             pointer = pointer->next;
337         }
338
339         pointer->next = node;
340     }
341 }
342
343 void AddAction(OCAction** head, OCAction* node)
344 {
345     OCAction *pointer = *head;
346     if (NULL == pointer)
347     {
348         *head = node;
349     }
350     else
351     {
352
353         while (pointer->next != NULL)
354         {
355             pointer = pointer->next;
356         }
357
358         pointer->next = node;
359     }
360 }
361
362 OCStackResult AddActionSet(OCActionSet **head, OCActionSet* node)
363 {
364     OCActionSet *pointer = *head;
365     OCActionSet *prev = NULL;
366     if(node == NULL)
367     {
368         return OC_STACK_ERROR;
369     }
370     if (NULL == pointer)
371     {
372         *head = node;
373     }
374     else
375     {
376         prev = pointer;
377         while (pointer != NULL)
378         {
379             // check the uniqeness of actionsetname.
380             if (strcmp(pointer->actionsetName, node->actionsetName) == 0)
381             {
382                 return OC_STACK_ERROR;
383             }
384
385             prev = pointer;
386             pointer = pointer->next;
387         }
388
389         prev->next = node;
390     }
391
392     return OC_STACK_OK;
393 }
394
395 void DeleteCapability(OCCapability *del)
396 {
397     OCFREE(del->capability)
398     del->capability = NULL;
399     OCFREE(del->status)
400     del->status = NULL;
401     OCFREE(del)
402 }
403
404 void DeleteAction(OCAction** action)
405 {
406     OCCapability* pointer = (*action)->head;
407     OCCapability* pDel = NULL;
408
409     while (pointer)
410     {
411         pDel = pointer;
412         pointer = pointer->next;
413
414         DeleteCapability(pDel);
415     }
416     OCFREE((*action)->resourceUri)
417     (*action)->next = NULL;
418     OCFREE(*action)
419 }
420
421 void DeleteActionSet(OCActionSet** actionset)
422 {
423     if(*actionset == NULL)
424         return;
425
426     OCAction* pointer = (*actionset)->head;
427     OCAction* pDel = NULL;
428
429     while (pointer)
430     {
431         pDel = pointer;
432         pointer = pointer->next;
433
434         DeleteAction(&pDel);
435     }
436     //    (*actionset)->head = NULL;
437     OCFREE((*actionset)->actionsetName)
438     OCFREE(*actionset)
439 }
440
441 OCStackResult FindAndDeleteActionSet(OCResource **resource,
442         const char * actionsetName)
443 {
444     if (*resource != NULL)
445     {
446         OCActionSet *pointer = NULL;
447         OCActionSet *pDel = NULL;
448
449         pointer = (*resource)->actionsetHead;
450
451         if (pointer == NULL)
452         {
453             return OC_STACK_ERROR;
454         }
455         else
456         {
457             if (strcmp(pointer->actionsetName, actionsetName) == 0)
458             {
459                 if (pointer->next != NULL)
460                     (*resource)->actionsetHead = pointer->next;
461                 else
462                     (*resource)->actionsetHead = NULL;
463
464                 DeleteActionSet(&pointer);
465             }
466             else if (pointer->next != NULL)
467             {
468                 while (pointer)
469                 {
470                     if (pointer->next != NULL)
471                     {
472                         if (strcmp(pointer->next->actionsetName, actionsetName)
473                                 == 0)
474                         {
475                             pDel = pointer->next;
476                             pointer->next = pointer->next->next;
477
478                             DeleteActionSet(&pDel);
479                         }
480                     }
481                     pointer = pointer->next;
482                 }
483             }
484
485             return OC_STACK_OK;
486         }
487
488     }
489     return OC_STACK_ERROR;
490 }
491
492 OCStackResult DeleteActionSets(OCResource** resource)
493 {
494     OCActionSet *pointer = (*resource)->actionsetHead;
495     OCActionSet *pDel = pointer;
496
497     while (pointer)
498     {
499         pDel = pointer;
500         pointer = pointer->next;
501
502         DeleteActionSet(&pDel);
503         pDel->next = NULL;
504     }
505
506     (*resource)->actionsetHead = NULL;
507     return OC_STACK_OK;
508 }
509
510 OCStackResult GetActionSet(const char *actionName, OCActionSet *head,
511         OCActionSet** actionset)
512 {
513     OCActionSet *pointer = head;
514
515     while (pointer)
516     {
517         if (strcmp(pointer->actionsetName, actionName) == 0)
518         {
519             *actionset = pointer;
520             return OC_STACK_OK;
521         }
522
523         pointer = pointer->next;
524     }
525
526     return OC_STACK_ERROR;
527
528 }
529
530 OCStackResult ExtractKeyValueFromRequest(char *request, char **key,
531         char **value)
532 {
533     OCStackResult result = OC_STACK_OK;
534     size_t length = 0;
535
536     char* pRequest = (char *) request + strlen(OIC_ACTION_PREFIX);
537     char* iterToken, *iterTokenPtr;
538
539     iterToken = (char *) strtok_r(pRequest, ":", &iterTokenPtr);
540     VARIFY_POINTER_NULL(iterToken, result, exit);
541     length = strlen(iterToken) + 1;
542
543     *key = (char *) OICMalloc(length);
544     VARIFY_POINTER_NULL(*key, result, exit)
545
546     strncpy(*key, iterToken + 1, length);
547     ((*key)[((length - 1) - 2)]) = '\0';
548
549     iterToken = (char *) strtok_r(NULL, "}", &iterTokenPtr);
550     VARIFY_POINTER_NULL(iterToken, result, exit);
551     length = strlen(iterToken) + 1;
552
553     *value = (char *) OICMalloc(length);
554     VARIFY_POINTER_NULL(*value, result, exit)
555
556     strncpy(*value, iterToken + 1, length);
557     ((*value)[((length - 1) - 2)]) = '\0';
558
559 exit:
560     if (result != OC_STACK_OK)
561     {
562         OCFREE(*key)
563         OCFREE(*value)
564     }
565
566     return result;
567 }
568
569 OCStackResult ExtractActionSetNameAndDelaytime(char *pChar, char **setName,
570         long int *pa)
571 {
572     char *token, *tokenPtr;
573     OCStackResult result = OC_STACK_OK;
574
575     token = (char*) strtok_r(pChar, ACTION_DELIMITER, &tokenPtr);
576     *setName = (char *) OICMalloc(strlen(token) + 1);
577     VARIFY_POINTER_NULL(*setName, result, exit)
578     VARIFY_PARAM_NULL(token, result, exit)
579     strncpy(*setName, token, strlen(token) + 1);
580
581     token = strtok_r(NULL, ACTION_DELIMITER, &tokenPtr);
582     VARIFY_POINTER_NULL(pa, result, exit)
583     VARIFY_PARAM_NULL(token, result, exit)
584     *pa = atoi(token);
585
586     return OC_STACK_OK;
587
588 exit:
589     OCFREE(*setName);
590     return result;
591 }
592
593 OCStackResult BuildActionSetFromString(OCActionSet **set, char* actiondesc)
594 {
595     OCStackResult result = OC_STACK_OK;
596
597     char *iterToken = NULL, *iterTokenPtr = NULL;
598     char *descIterToken = NULL, *descIterTokenPtr = NULL;
599     char *attrIterToken = NULL, *attrIterTokenPtr = NULL;
600     char *desc = NULL, *attr = NULL;
601     char *key = NULL, *value = NULL;
602
603     OCAction *action = NULL;
604     OCCapability *capa = NULL;
605
606     OC_LOG(INFO, TAG, PCF("Build ActionSet Instance."));
607
608     *set = (OCActionSet*) OICMalloc(sizeof(OCActionSet));
609     VARIFY_POINTER_NULL(*set, result, exit)
610
611     iterToken = (char *) strtok_r(actiondesc, ACTION_DELIMITER, &iterTokenPtr);
612
613     // ActionSet Name
614     memset(*set, 0, sizeof(OCActionSet));
615     (*set)->actionsetName = (char *) OICMalloc(strlen(iterToken) + 1);
616     VARIFY_POINTER_NULL((*set)->actionsetName, result, exit)
617     VARIFY_PARAM_NULL(iterToken, result, exit)
618     strncpy((*set)->actionsetName, iterToken, strlen(iterToken) + 1);
619
620     // Time info. for Scheduled/Recursive Group action.
621     // d is meant Day of the week.
622     // T is meant ActionType.
623     // yyyy-mm-dd hh:mm:ss d
624     iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
625     VARIFY_PARAM_NULL(iterToken, result, exit)
626 #ifndef WITH_ARDUINO
627     sscanf(iterToken, "%ld %u", &(*set)->timesteps, &(*set)->type);
628 #endif
629
630     OC_LOG_V(INFO, TAG, "ActionSet Name : %s", (*set)->actionsetName);
631
632     iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
633     while (iterToken)
634     {
635         desc = (char *) OICMalloc(strlen(iterToken) + 1);
636         VARIFY_POINTER_NULL(desc, result, exit)
637         VARIFY_PARAM_NULL(desc, result, exit)
638         strncpy(desc, iterToken, strlen(iterToken) + 1);
639         descIterToken = (char *) strtok_r(desc, ATTR_DELIMITER,
640                 &descIterTokenPtr);
641         while (descIterToken)
642         {
643             attr = (char *) OICMalloc(strlen(descIterToken) + 1);
644             VARIFY_POINTER_NULL(attr, result, exit)
645             VARIFY_PARAM_NULL(descIterToken, result, exit)
646             strncpy(attr, descIterToken, strlen(descIterToken) + 1);
647
648             attrIterToken = (char *) strtok_r(attr, ATTR_ASSIGN,
649                     &attrIterTokenPtr);
650             key = (char *) OICMalloc(strlen(attrIterToken) + 1);
651             VARIFY_POINTER_NULL(key, result, exit)
652             VARIFY_PARAM_NULL(attrIterToken, result, exit)
653             strncpy(key, attrIterToken, strlen(attrIterToken) + 1);
654
655             attrIterToken = (char *) strtok_r(NULL, ATTR_ASSIGN,
656                     &attrIterTokenPtr);
657             value = (char *) OICMalloc(strlen(attrIterToken) + 1);
658             VARIFY_POINTER_NULL(value, result, exit)
659             VARIFY_PARAM_NULL(attrIterToken, result, exit)
660             strncpy(value, attrIterToken, strlen(attrIterToken) + 1);
661
662             if (strcmp(key, "uri") == 0)
663             {
664                 OC_LOG(INFO, TAG, PCF("Build OCAction Instance."));
665
666                 if(action)
667                 {
668                     OICFree(action->resourceUri);
669                     OICFree(action);
670                 }
671                 action = (OCAction*) OICMalloc(sizeof(OCAction));
672                 VARIFY_POINTER_NULL(action, result, exit)
673                 memset(action, 0, sizeof(OCAction));
674                 action->resourceUri = (char *) OICMalloc(strlen(value) + 1);
675                 VARIFY_POINTER_NULL(action->resourceUri, result, exit)
676                 VARIFY_PARAM_NULL(value, result, exit)
677                 strncpy(action->resourceUri, value, strlen(value) + 1);
678             }
679             else
680             {
681                 if ((key != NULL) && (value != NULL))
682                 {
683                     OC_LOG(INFO, TAG, PCF("Build OCCapability Instance."));
684
685                     capa = (OCCapability*) OICMalloc(sizeof(OCCapability));
686                     VARIFY_POINTER_NULL(capa, result, exit)
687                     memset(capa, 0, sizeof(OCCapability));
688
689                     capa->capability = (char *) OICMalloc(strlen(key) + 1);
690                     VARIFY_POINTER_NULL(capa->capability, result, exit)
691                     VARIFY_PARAM_NULL(key, result, exit)
692                     strncpy(capa->capability, key, strlen(key) + 1);
693
694                     capa->status = (char *) OICMalloc(strlen(value) + 1);
695                     VARIFY_POINTER_NULL(capa->status, result, exit)
696                     VARIFY_PARAM_NULL(value, result, exit)
697                     strncpy(capa->status, value, strlen(value) + 1);
698
699                     VARIFY_POINTER_NULL(action, result, exit)
700
701                     AddCapability(&action->head, capa);
702                 }
703             }
704
705             OCFREE(key)
706             OCFREE(value)
707             OCFREE(attr)
708
709             descIterToken = (char *) strtok_r(NULL, ATTR_DELIMITER,
710                     &descIterTokenPtr);
711         }
712
713         AddAction(&(*set)->head, action);
714         iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
715         OCFREE(desc);
716     }
717
718     return OC_STACK_OK;
719 exit:
720     OCFREE(attr)
721     OCFREE(desc)
722     OCFREE(capa)
723     OCFREE(action)
724     OCFREE(*set)
725     OCFREE(key)
726     OCFREE(value)
727     OCFREE(attr)
728
729     return result;
730 }
731
732 OCStackResult BuildStringFromActionSet(OCActionSet* actionset, char** desc)
733 {
734     // Can't use the macros here as they are hardcoded to 'exit' and will
735     // result in dereferencing a null pointer.
736     if (!actionset || !desc)
737     {
738         return OC_STACK_INVALID_PARAM;
739     }
740     char temp[1024] = { 0 };
741     size_t remaining = sizeof(temp) - 1;
742     OCStackResult res = OC_STACK_ERROR;
743
744     OCAction *action = actionset->head;
745
746     if (remaining >= strlen(actionset->actionsetName) + 1)
747     {
748         strcat(temp, actionset->actionsetName);
749         remaining -= strlen(actionset->actionsetName);
750         strcat(temp, ACTION_DELIMITER);
751         remaining--;
752     }
753     else
754     {
755         res = OC_STACK_ERROR;
756         goto exit;
757     }
758
759     while (action != NULL)
760     {
761         if (remaining < (strlen("uri=") + strlen(action->resourceUri) + 1))
762         {
763             res = OC_STACK_ERROR;
764             goto exit;
765         }
766         strcat(temp, "uri=");
767         remaining -= strlen("uri=");
768         strcat(temp, action->resourceUri);
769         remaining -= strlen(action->resourceUri);
770         strcat(temp, "|");
771         remaining--;
772
773         OCCapability *capas = action->head;
774         while (capas != NULL)
775         {
776             if (remaining < (strlen(capas->capability)
777                              + 1 + strlen(capas->status)))
778             {
779                 res = OC_STACK_ERROR;
780                 goto exit;
781             }
782
783             strcat(temp, capas->capability);
784             remaining -= strlen(capas->capability);
785             strcat(temp, "=");
786             remaining--;
787             strcat(temp, capas->status);
788             remaining -= strlen(capas->status);
789
790             capas = capas->next;
791             if (capas != NULL)
792             {
793                 if (remaining < 1)
794                 {
795                     res = OC_STACK_ERROR;
796                     goto exit;
797                 }
798                 strcat(temp, "|");
799             }
800         }
801
802         action = action->next;
803         if (action != NULL)
804         {
805             if (remaining < strlen(ACTION_DELIMITER))
806             {
807                 res = OC_STACK_ERROR;
808                 goto exit;
809             }
810             strcat(temp, ACTION_DELIMITER);
811             remaining--;
812         }
813     }
814
815     *desc = OICStrdup(temp);
816     VARIFY_POINTER_NULL(*desc, res, exit);
817
818     return OC_STACK_OK;
819
820 exit:
821     OCFREE(*desc);
822     return res;
823 }
824
825 OCStackApplicationResult ActionSetCB(void* context, OCDoHandle handle,
826         OCClientResponse* clientResponse)
827 {
828     (void)context;
829     (void)clientResponse;
830     OC_LOG(INFO, TAG, PCF("Entering BuildActionJSON"));
831
832     ClientRequestInfo *info = GetClientRequestInfo(clientRequstList, handle);
833
834     if (info)
835     {
836         int idx;
837
838         unsigned char *responseJson = NULL;
839         // TODO: Figure out what this does, change implementation
840         //responseJson = (unsigned char *) OICMalloc(
841         //        (unsigned int) (strlen((char *) clientResponse->resJSONPayload)
842         //                + 1));
843
844         if( responseJson == NULL )
845             return OC_STACK_DELETE_TRANSACTION;
846
847         // We need the body of response.
848         // Copy the body from the response
849         // TODO: Taken out
850         //strcpy((char *) responseJson,
851         //        ((char *) clientResponse->resJSONPayload + OC_JSON_PREFIX_LEN));
852         //idx = strlen((char *) responseJson) - OC_JSON_SUFFIX_LEN;
853         // And insert NULL at the end of body.
854         (responseJson[idx]) = 0;
855
856         OCEntityHandlerResponse response = { 0 };
857         response.ehResult = OC_EH_OK;
858         // TODO: Removing payload size, waht goes here?
859         // response.payload = (char*)responseJson;
860         //response.payloadSize = (unsigned int) strlen((char *) responseJson) + 1;
861         response.persistentBufferFlag = 0;
862         response.requestHandle = (OCRequestHandle) info->ehRequest;
863         response.resourceHandle = (OCResourceHandle) info->collResource;
864
865         OCDoResponse(&response);
866
867         RemoveClientRequestInfo(&clientRequstList, info);
868         OCFREE(info)
869         OCFREE(responseJson)
870     }
871
872     return OC_STACK_KEEP_TRANSACTION;
873 }
874
875 void ActionSetCD(void *context)
876 {
877     (void)context;
878 }
879
880 OCStackResult BuildActionJSON(OCAction* action, unsigned char* bufferPtr,
881         uint16_t *remaining)
882 {
883     OCStackResult ret = OC_STACK_ERROR;
884     cJSON *json;
885     cJSON *body;
886
887     char *jsonStr;
888     uint16_t jsonLen;
889
890     OC_LOG(INFO, TAG, PCF("Entering BuildActionJSON"));
891     json = cJSON_CreateObject();
892
893     cJSON_AddItemToObject(json, "rep", body = cJSON_CreateObject());
894
895     OCCapability* pointerCapa = action->head;
896     while (pointerCapa)
897     {
898         cJSON_AddStringToObject(body, pointerCapa->capability,
899                 pointerCapa->status);
900         pointerCapa = pointerCapa->next;
901     }
902
903     jsonStr = cJSON_PrintUnformatted(json);
904
905     jsonLen = strlen(jsonStr);
906     if (jsonLen < *remaining)
907     {
908         strcat((char*) bufferPtr, jsonStr);
909         *remaining -= jsonLen;
910         bufferPtr += jsonLen;
911         ret = OC_STACK_OK;
912     }
913
914     cJSON_Delete(json);
915     free(jsonStr);
916
917     return ret;
918 }
919
920 unsigned int GetNumOfTargetResource(OCAction *actionset)
921 {
922     int numOfResource = 0;
923
924     OCAction *pointerAction = actionset;
925
926     while (pointerAction != NULL)
927     {
928         numOfResource++;
929         pointerAction = pointerAction->next;
930     }
931
932     return numOfResource;
933 }
934
935
936 #define DEFAULT_CONTEXT_VALUE 0x99
937
938 OCStackResult SendAction(OCDoHandle *handle, const char *targetUri,
939         const unsigned char *action)
940 {
941     (void)handle;
942     (void)targetUri;
943     (void)action;
944     // TODO: disabled since this is no longer compatible
945     return OC_STACK_NOTIMPL;
946 }
947
948 OCStackResult DoAction(OCResource* resource, OCActionSet* actionset,
949         OCServerRequest* requestHandle)
950 {
951     OCStackResult result = OC_STACK_ERROR;
952     OCAction *pointerAction = actionset->head;
953
954     while (pointerAction != NULL)
955     {
956         unsigned char actionDesc[MAX_RESPONSE_LENGTH] = { 0 };
957         unsigned char* actionDescPtr = actionDesc;
958         uint16_t remaining = MAX_RESPONSE_LENGTH;
959
960         strncpy((char *) actionDescPtr, (const char *) OC_JSON_PREFIX,
961                 strlen((const char *) OC_JSON_PREFIX) + 1);
962         BuildActionJSON(pointerAction, actionDescPtr, &remaining);
963         strncat((char *) actionDescPtr, (const char *) OC_JSON_SUFFIX,
964                 strlen((const char *) OC_JSON_SUFFIX));
965
966         ClientRequestInfo *info = (ClientRequestInfo *) OICMalloc(
967                 sizeof(ClientRequestInfo));
968
969         if( info == NULL )
970             return OC_STACK_NO_MEMORY;
971
972         memset(info, 0, sizeof(ClientRequestInfo));
973
974         info->collResource = resource;
975         info->ehRequest = requestHandle;
976
977         result = SendAction(&info->required, pointerAction->resourceUri,
978                 actionDescPtr);
979         if (result != OC_STACK_OK)
980         {
981             OICFree(info);
982             return result;
983         }
984
985         AddClientRequestInfo(&clientRequstList, info);
986
987         pointerAction = pointerAction->next;
988     }
989
990     return result;
991 }
992
993 void DoScheduledGroupAction()
994 {
995     OC_LOG(INFO, TAG, PCF("DoScheduledGroupAction Entering..."));
996     ScheduledResourceInfo* info = GetScheduledResource(scheduleResourceList);
997
998     if (info == NULL)
999     {
1000         OC_LOG(INFO, TAG, PCF("Target resource is NULL"));
1001         goto exit;
1002     }
1003     else if (info->resource == NULL)
1004     {
1005         OC_LOG(INFO, TAG, PCF("Target resource is NULL"));
1006         goto exit;
1007     }
1008     else if (info->actionset == NULL)
1009     {
1010         OC_LOG(INFO, TAG, PCF("Target ActionSet is NULL"));
1011         goto exit;
1012     }
1013     else if (info->ehRequest == NULL)
1014     {
1015         OC_LOG(INFO, TAG, PCF("Target ActionSet is NULL"));
1016         goto exit;
1017     }
1018 #ifndef WITH_ARDUINO
1019     pthread_mutex_lock(&lock);
1020 #endif
1021     DoAction(info->resource, info->actionset, info->ehRequest);
1022 #ifndef WITH_ARDUINO
1023     pthread_mutex_unlock(&lock);
1024 #endif
1025
1026     if (info->actionset->type == RECURSIVE)
1027     {
1028         ScheduledResourceInfo *schedule;
1029         schedule = (ScheduledResourceInfo *) OICMalloc(
1030                 sizeof(ScheduledResourceInfo));
1031
1032         if (schedule)
1033         {
1034             OC_LOG(INFO, TAG, PCF("Building New Call Info."));
1035             memset(schedule, 0, sizeof(ScheduledResourceInfo));
1036
1037             if (info->actionset->timesteps > 0)
1038             {
1039 #ifndef WITH_ARDUINO
1040                 pthread_mutex_lock(&lock);
1041 #endif
1042                 schedule->resource = info->resource;
1043                 schedule->actionset = info->actionset;
1044                 schedule->ehRequest = info->ehRequest;
1045
1046                 schedule->time = registerTimer(info->actionset->timesteps,
1047                         &schedule->timer_id,
1048                         &DoScheduledGroupAction);
1049
1050                 OC_LOG(INFO, TAG, PCF("Reregisteration."));
1051 #ifndef WITH_ARDUINO
1052                 pthread_mutex_unlock(&lock);
1053 #endif
1054                 AddScheduledResource(&scheduleResourceList, schedule);
1055             }
1056             else
1057             {
1058                 OICFree(schedule);
1059             }
1060         }
1061     }
1062
1063     RemoveScheduledResource(&scheduleResourceList, info);
1064
1065     exit:
1066
1067     return;
1068 }
1069
1070 OCStackResult BuildCollectionGroupActionJSONResponse(
1071         OCMethod method/*OCEntityHandlerFlag flag*/, OCResource *resource,
1072         OCEntityHandlerRequest *ehRequest)
1073 {
1074     OCStackResult stackRet = OC_STACK_ERROR;
1075
1076     OC_LOG(INFO, TAG, PCF("Group Action is requested."));
1077     // if (stackRet == OC_STACK_OK)
1078     {
1079         char *doWhat = NULL;
1080         char *details = NULL;
1081
1082         size_t bufferLength = 0;
1083         unsigned char buffer[MAX_RESPONSE_LENGTH] = { 0 };
1084
1085         OCResource * collResource = (OCResource *) ehRequest->resource;
1086
1087         char *jsonResponse;
1088
1089         stackRet = OC_STACK_NOTIMPL;
1090         // TODO: Fix?
1091         //stackRet = ExtractKeyValueFromRequest((char *) ehRequest->reqJSONPayload,
1092         //        &doWhat, &details);
1093
1094         if(stackRet != OC_STACK_OK)
1095         {
1096             OC_LOG_V(ERROR, TAG, "ExtractKeyValueFromRequest failed: %d", stackRet);
1097             return stackRet;
1098         }
1099
1100         stackRet = OC_STACK_ERROR;
1101
1102         cJSON *json;
1103         cJSON *format;
1104
1105         if (method == OC_REST_PUT)
1106         {
1107             json = cJSON_CreateObject();
1108             cJSON_AddStringToObject(json, "href", resource->uri);
1109             cJSON_AddItemToObject(json, "rep", format = cJSON_CreateObject());
1110
1111             OC_LOG(INFO, TAG, PCF("Group Action[PUT]."));
1112
1113             if (strcmp(doWhat, ACTIONSET) == 0)
1114             {
1115                 OCActionSet *actionSet = NULL;
1116                 stackRet = BuildActionSetFromString(&actionSet, details);
1117
1118                 if(stackRet == OC_STACK_OK)
1119                 {
1120                     if (actionSet != NULL)
1121                     {
1122                         stackRet = AddActionSet(&resource->actionsetHead,
1123                                 actionSet);
1124                         if (stackRet == OC_STACK_ERROR)
1125                         {
1126                             if(actionSet != NULL)
1127                             {
1128                                 DeleteActionSet( &actionSet );
1129                             }
1130                             OC_LOG(INFO, TAG, PCF("Duplicated ActionSet "));
1131                         }
1132                     }
1133                 }
1134                 else
1135                 {
1136                     stackRet = OC_STACK_ERROR;
1137                 }
1138
1139             }
1140             else if (strcmp(doWhat, DELETE_ACTIONSET) == 0)
1141             {
1142                 if (FindAndDeleteActionSet(&resource, details) == OC_STACK_OK)
1143                 {
1144                     stackRet = OC_STACK_OK;
1145                 }
1146                 else
1147                 {
1148                     stackRet = OC_STACK_ERROR;
1149                 }
1150             }
1151
1152             jsonResponse = cJSON_Print(json);
1153             cJSON_Delete(json);
1154
1155             OICStrcat((char*)buffer, sizeof(buffer), jsonResponse);
1156
1157             bufferLength = strlen((const char *) buffer);
1158             if (bufferLength > 0)
1159             {
1160                 OCEntityHandlerResponse response = { 0 };
1161                 if(stackRet == OC_STACK_OK)
1162                     response.ehResult = OC_EH_OK;
1163                 else
1164                     response.ehResult = OC_EH_ERROR;
1165                 // TODO: Fix
1166                 //response.payload = (char*)buffer;
1167                 //response.payloadSize = bufferLength + 1;
1168                 response.persistentBufferFlag = 0;
1169                 response.requestHandle =
1170                         (OCRequestHandle) ehRequest->requestHandle;
1171                 response.resourceHandle = (OCResourceHandle) collResource;
1172                 stackRet = OCDoResponse(&response);
1173             }
1174         }
1175
1176         if (method == OC_REST_POST)
1177         {
1178             OCActionSet *actionset = NULL;
1179
1180             json = cJSON_CreateObject();
1181             cJSON_AddStringToObject(json, "href", resource->uri);
1182
1183             if ((strcmp(doWhat, DO_ACTION) == 0)
1184                     || (strcmp(doWhat, "DoScheduledAction") == 0))
1185             {
1186                 char *pActionsetName = NULL;
1187                 long int delay = -1;
1188
1189                 if (strcmp(doWhat, "DoScheduledAction") == 0)
1190                 {
1191                     stackRet = ExtractActionSetNameAndDelaytime(details,
1192                             &pActionsetName, &delay);
1193
1194                     OCFREE(details)
1195                     details = pActionsetName;
1196                 }
1197                 else
1198                 {
1199                     stackRet = OC_STACK_OK;
1200                 }
1201
1202                 if (stackRet == OC_STACK_OK)
1203                 {
1204                     if (GetActionSet(details, resource->actionsetHead,
1205                             &actionset) != OC_STACK_OK)
1206                     {
1207                         OC_LOG(INFO, TAG, PCF("ERROR"));
1208                         stackRet = OC_STACK_ERROR;
1209                     }
1210
1211                     if (actionset == NULL)
1212                     {
1213                         OC_LOG(INFO, TAG, PCF("Cannot Find ActionSet"));
1214                         stackRet = OC_STACK_ERROR;
1215                     }
1216                     else
1217                     {
1218                         OC_LOG(INFO, TAG, PCF("Group Action[POST]."));
1219                         if (actionset->type == NONE)
1220                         {
1221                             OC_LOG_V(INFO, TAG, "Execute ActionSet : %s",
1222                                     actionset->actionsetName);
1223                             unsigned int num = GetNumOfTargetResource(
1224                                     actionset->head);
1225
1226                             ((OCServerRequest *) ehRequest->requestHandle)->ehResponseHandler =
1227                                     HandleAggregateResponse;
1228                             ((OCServerRequest *) ehRequest->requestHandle)->numResponses =
1229                                     num + 1;
1230
1231                             DoAction(resource, actionset,
1232                                     (OCServerRequest*) ehRequest->requestHandle);
1233                             stackRet = OC_STACK_OK;
1234                         }
1235                         else
1236                         {
1237                             OC_LOG_V(INFO, TAG, "Execute Scheduled ActionSet : %s",
1238                                     actionset->actionsetName);
1239
1240                             delay =
1241                                     (delay == -1 ? actionset->timesteps : delay);
1242
1243                             ScheduledResourceInfo *schedule;
1244                             schedule = (ScheduledResourceInfo *) OICMalloc(
1245                                     sizeof(ScheduledResourceInfo));
1246
1247                             if (schedule)
1248                             {
1249                                 OC_LOG(INFO, TAG, PCF("Building New Call Info."));
1250                                 memset(schedule, 0,
1251                                         sizeof(ScheduledResourceInfo));
1252
1253                                 schedule->resource = resource;
1254                                 schedule->actionset = actionset;
1255                                 schedule->ehRequest =
1256                                         (OCServerRequest*) ehRequest->requestHandle;
1257
1258                                 if (delay > 0)
1259                                 {
1260                                     OC_LOG_V(INFO, TAG, "delay_time is %lf seconds.",
1261                                             actionset->timesteps);
1262
1263                                     schedule->time = registerTimer(delay,
1264                                             &schedule->timer_id,
1265                                             &DoScheduledGroupAction);
1266
1267                                     AddScheduledResource(&scheduleResourceList,
1268                                             schedule);
1269                                     stackRet = OC_STACK_OK;
1270                                 }
1271                                 else
1272                                 {
1273                                     stackRet = OC_STACK_ERROR;
1274                                 }
1275                             }
1276                         }
1277                     }
1278                 }
1279             }
1280             else if (strcmp(doWhat, "CancelAction") == 0)
1281             {
1282                 ScheduledResourceInfo *info =
1283                         GetScheduledResourceByActionSetName(scheduleResourceList, details);
1284
1285                 if(info != NULL)
1286                 {
1287                     unregisterTimer(info->timer_id);
1288
1289                     RemoveScheduledResource(&scheduleResourceList, info);
1290                     stackRet = OC_STACK_OK;
1291                 }
1292                 else
1293                 {
1294                     stackRet = OC_STACK_ERROR;
1295                 }
1296             }
1297
1298             else if (strcmp(doWhat, GET_ACTIONSET) == 0)
1299             {
1300                 char *plainText = NULL;
1301                 OCActionSet *actionset = NULL;
1302
1303                 cJSON_AddItemToObject(json, "rep", format =
1304                         cJSON_CreateObject());
1305                 GetActionSet(details, resource->actionsetHead, &actionset);
1306                 if (actionset != NULL)
1307                 {
1308                     BuildStringFromActionSet(actionset, &plainText);
1309
1310                     if (plainText != NULL)
1311                     {
1312                         cJSON_AddStringToObject(format, ACTIONSET, plainText);
1313                     }
1314                     OICFree(plainText);
1315                     stackRet = OC_STACK_OK;
1316                 }
1317             }
1318
1319
1320             jsonResponse = cJSON_Print(json);
1321             cJSON_Delete(json);
1322
1323             OICStrcat((char*)buffer, sizeof(buffer), jsonResponse);
1324
1325             bufferLength = strlen((const char *) buffer);
1326             if (bufferLength > 0)
1327             {
1328                 OCEntityHandlerResponse response = { 0 };
1329                 if(stackRet == OC_STACK_OK)
1330                     response.ehResult = OC_EH_OK;
1331                 else
1332                     response.ehResult = OC_EH_ERROR;
1333                 // TODO: Implement
1334                 //response.payload = (char *)buffer;
1335                 //response.payloadSize = bufferLength + 1;
1336                 response.persistentBufferFlag = 0;
1337                 response.requestHandle =
1338                         (OCRequestHandle) ehRequest->requestHandle;
1339                 response.resourceHandle = (OCResourceHandle) collResource;
1340                 stackRet = OCDoResponse(&response);
1341             }
1342         }
1343
1344         OCFREE(doWhat)
1345         OCFREE(details)
1346     }
1347
1348     return stackRet;
1349 }