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