Merge branch 'remote-access2'
[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 "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, "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, "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, "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, "Cannot Find Call Info.");
174     }
175     return tmp;
176 }
177
178 ScheduledResourceInfo* GetScheduledResourceByActionSetName(ScheduledResourceInfo *head, char *setName)
179 {
180     OC_LOG(INFO, TAG, "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, "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, "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, "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     OCFREE(actionSetStr);
604
605     return result;
606 }
607
608 OCStackResult ExtractActionSetNameAndDelaytime(char *pChar, char **setName,
609         long int *pa)
610 {
611     char *token = NULL, *tokenPtr = NULL;
612     OCStackResult result = OC_STACK_OK;
613
614     token = (char*) strtok_r(pChar, ACTION_DELIMITER, &tokenPtr);
615     VARIFY_POINTER_NULL(token, result, exit)
616
617     *setName = (char *) OICMalloc(strlen(token) + 1);
618     VARIFY_POINTER_NULL(*setName, result, exit)
619     VARIFY_PARAM_NULL(token, result, exit)
620     strncpy(*setName, token, strlen(token) + 1);
621
622     token = strtok_r(NULL, ACTION_DELIMITER, &tokenPtr);
623     VARIFY_POINTER_NULL(pa, result, exit)
624     VARIFY_PARAM_NULL(token, result, exit)
625     *pa = atoi(token);
626
627     return OC_STACK_OK;
628
629 exit:
630     OCFREE(*setName);
631     return result;
632 }
633
634 OCStackResult BuildActionSetFromString(OCActionSet **set, char* actiondesc)
635 {
636     OCStackResult result = OC_STACK_OK;
637
638     char *iterToken = NULL, *iterTokenPtr = NULL;
639     char *descIterToken = NULL, *descIterTokenPtr = NULL;
640     char *attrIterToken = NULL, *attrIterTokenPtr = NULL;
641     char *desc = NULL, *attr = NULL;
642     char *key = NULL, *value = NULL;
643
644     OCAction *action = NULL;
645     OCCapability *capa = NULL;
646
647     OC_LOG(INFO, TAG, "Build ActionSet Instance.");
648
649     *set = (OCActionSet*) OICMalloc(sizeof(OCActionSet));
650     VARIFY_POINTER_NULL(*set, result, exit)
651
652     iterToken = (char *) strtok_r(actiondesc, ACTION_DELIMITER, &iterTokenPtr);
653
654     // ActionSet Name
655     memset(*set, 0, sizeof(OCActionSet));
656     (*set)->actionsetName = (char *) OICMalloc(strlen(iterToken) + 1);
657     VARIFY_POINTER_NULL((*set)->actionsetName, result, exit)
658     VARIFY_PARAM_NULL(iterToken, result, exit)
659     strncpy((*set)->actionsetName, iterToken, strlen(iterToken) + 1);
660
661     // Time info. for Scheduled/Recursive Group action.
662     // d is meant Day of the week.
663     // T is meant ActionType.
664     // yyyy-mm-dd hh:mm:ss d
665     iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
666     VARIFY_PARAM_NULL(iterToken, result, exit)
667 #ifndef WITH_ARDUINO
668     if( 2 != sscanf(iterToken, "%ld %u", &(*set)->timesteps, &(*set)->type) )
669     {
670         // If the return value should be 2, the number of items in the argument. Otherwise, it fails.
671         goto exit;
672     }
673 #endif
674
675     OC_LOG_V(INFO, TAG, "ActionSet Name : %s", (*set)->actionsetName);
676
677     iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
678     while (iterToken)
679     {
680         desc = (char *) OICMalloc(strlen(iterToken) + 1);
681         VARIFY_POINTER_NULL(desc, result, exit)
682         VARIFY_PARAM_NULL(desc, result, exit)
683         strncpy(desc, iterToken, strlen(iterToken) + 1);
684         descIterToken = (char *) strtok_r(desc, ATTR_DELIMITER,
685                 &descIterTokenPtr);
686         while (descIterToken)
687         {
688             attr = (char *) OICMalloc(strlen(descIterToken) + 1);
689             VARIFY_POINTER_NULL(attr, result, exit)
690             VARIFY_PARAM_NULL(descIterToken, result, exit)
691             strncpy(attr, descIterToken, strlen(descIterToken) + 1);
692
693             attrIterToken = (char *) strtok_r(attr, ATTR_ASSIGN,
694                     &attrIterTokenPtr);
695             VARIFY_POINTER_NULL(attrIterToken, result, exit);
696
697             key = (char *) OICMalloc(strlen(attrIterToken) + 1);
698             VARIFY_POINTER_NULL(key, result, exit)
699             VARIFY_PARAM_NULL(attrIterToken, result, exit)
700             strncpy(key, attrIterToken, strlen(attrIterToken) + 1);
701
702             attrIterToken = (char *) strtok_r(NULL, ATTR_ASSIGN,
703                     &attrIterTokenPtr);
704             value = (char *) OICMalloc(strlen(attrIterToken) + 1);
705             VARIFY_POINTER_NULL(value, result, exit)
706             VARIFY_PARAM_NULL(attrIterToken, result, exit)
707             strncpy(value, attrIterToken, strlen(attrIterToken) + 1);
708
709             if (strcmp(key, "uri") == 0)
710             {
711                 OC_LOG(INFO, TAG, "Build OCAction Instance.");
712
713                 if(action)
714                 {
715                     OICFree(action->resourceUri);
716                     OICFree(action);
717                 }
718                 action = (OCAction*) OICMalloc(sizeof(OCAction));
719                 VARIFY_POINTER_NULL(action, result, exit)
720                 memset(action, 0, sizeof(OCAction));
721                 action->resourceUri = (char *) OICMalloc(strlen(value) + 1);
722                 VARIFY_POINTER_NULL(action->resourceUri, result, exit)
723                 VARIFY_PARAM_NULL(value, result, exit)
724                 strncpy(action->resourceUri, value, strlen(value) + 1);
725             }
726             else
727             {
728                 if ((key != NULL) && (value != NULL))
729                 {
730                     OC_LOG(INFO, TAG, "Build OCCapability Instance.");
731
732                     capa = (OCCapability*) OICMalloc(sizeof(OCCapability));
733                     VARIFY_POINTER_NULL(capa, result, exit)
734                     memset(capa, 0, sizeof(OCCapability));
735
736                     capa->capability = (char *) OICMalloc(strlen(key) + 1);
737                     VARIFY_POINTER_NULL(capa->capability, result, exit)
738                     VARIFY_PARAM_NULL(key, result, exit)
739                     strncpy(capa->capability, key, strlen(key) + 1);
740
741                     capa->status = (char *) OICMalloc(strlen(value) + 1);
742                     VARIFY_POINTER_NULL(capa->status, result, exit)
743                     VARIFY_PARAM_NULL(value, result, exit)
744                     strncpy(capa->status, value, strlen(value) + 1);
745
746                     VARIFY_POINTER_NULL(action, result, exit)
747
748                     AddCapability(&action->head, capa);
749                 }
750             }
751
752             OCFREE(key)
753             OCFREE(value)
754             OCFREE(attr)
755
756             descIterToken = (char *) strtok_r(NULL, ATTR_DELIMITER,
757                     &descIterTokenPtr);
758         }
759
760         AddAction(&(*set)->head, action);
761         iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
762         OCFREE(desc);
763     }
764
765     return OC_STACK_OK;
766 exit:
767     OCFREE(attr)
768     OCFREE(desc)
769     OCFREE(capa)
770     OCFREE(action)
771     OCFREE(*set)
772     OCFREE(key)
773     OCFREE(value)
774     OCFREE(attr)
775
776     return result;
777 }
778
779 OCStackResult BuildStringFromActionSet(OCActionSet* actionset, char** desc)
780 {
781     // Can't use the macros here as they are hardcoded to 'exit' and will
782     // result in dereferencing a null pointer.
783     if (!actionset || !desc)
784     {
785         return OC_STACK_INVALID_PARAM;
786     }
787     char temp[1024] = { 0 };
788     size_t remaining = sizeof(temp) - 1;
789     OCStackResult res = OC_STACK_ERROR;
790
791     OCAction *action = actionset->head;
792
793     if (remaining >= strlen(actionset->actionsetName) + 1)
794     {
795         strcat(temp, actionset->actionsetName);
796         remaining -= strlen(actionset->actionsetName);
797         strcat(temp, ACTION_DELIMITER);
798         remaining--;
799     }
800     else
801     {
802         res = OC_STACK_ERROR;
803         goto exit;
804     }
805
806     while (action != NULL)
807     {
808         if (remaining < (strlen("uri=") + strlen(action->resourceUri) + 1))
809         {
810             res = OC_STACK_ERROR;
811             goto exit;
812         }
813         strcat(temp, "uri=");
814         remaining -= strlen("uri=");
815         strcat(temp, action->resourceUri);
816         remaining -= strlen(action->resourceUri);
817         strcat(temp, "|");
818         remaining--;
819
820         OCCapability *capas = action->head;
821         while (capas != NULL)
822         {
823             if (remaining < (strlen(capas->capability)
824                              + 1 + strlen(capas->status)))
825             {
826                 res = OC_STACK_ERROR;
827                 goto exit;
828             }
829
830             strcat(temp, capas->capability);
831             remaining -= strlen(capas->capability);
832             strcat(temp, "=");
833             remaining--;
834             strcat(temp, capas->status);
835             remaining -= strlen(capas->status);
836
837             capas = capas->next;
838             if (capas != NULL)
839             {
840                 if (remaining < 1)
841                 {
842                     res = OC_STACK_ERROR;
843                     goto exit;
844                 }
845                 strcat(temp, "|");
846             }
847         }
848
849         action = action->next;
850         if (action != NULL)
851         {
852             if (remaining < strlen(ACTION_DELIMITER))
853             {
854                 res = OC_STACK_ERROR;
855                 goto exit;
856             }
857             strcat(temp, ACTION_DELIMITER);
858             remaining--;
859         }
860     }
861
862     *desc = OICStrdup(temp);
863     VARIFY_POINTER_NULL(*desc, res, exit);
864
865     return OC_STACK_OK;
866
867 exit:
868     OCFREE(*desc);
869     return res;
870 }
871
872 OCStackApplicationResult ActionSetCB(void* context, OCDoHandle handle,
873         OCClientResponse* clientResponse)
874 {
875     (void)context;
876     (void)clientResponse;
877     OC_LOG(INFO, TAG, "Entering ActionSetCB");
878
879     ClientRequestInfo *info = GetClientRequestInfo(clientRequstList, handle);
880
881     if (info)
882     {
883         OCEntityHandlerResponse response = { 0 };
884
885         response.ehResult = OC_EH_OK;
886
887         if(NULL == clientResponse->payload)
888         {
889             OC_LOG(ERROR, TAG, "Error sending response");
890             return OC_STACK_DELETE_TRANSACTION;
891         }
892
893         // Format the response.  Note this requires some info about the request
894         response.requestHandle = info->ehRequest;
895         response.resourceHandle = info->collResource;
896         response.payload = clientResponse->payload;
897         response.numSendVendorSpecificHeaderOptions = 0;
898         memset(response.sendVendorSpecificHeaderOptions, 0,
899                 sizeof response.sendVendorSpecificHeaderOptions);
900         memset(response.resourceUri, 0, sizeof response.resourceUri);
901         // Indicate that response is NOT in a persistent buffer
902         response.persistentBufferFlag = 0;
903
904         // Send the response
905         if (OCDoResponse(&response) != OC_STACK_OK)
906         {
907             OC_LOG(ERROR, TAG, "Error sending response");
908             return OC_STACK_DELETE_TRANSACTION;
909         }
910
911         RemoveClientRequestInfo(&clientRequstList, info);
912         OCFREE(info)
913     }
914
915     return OC_STACK_KEEP_TRANSACTION;
916 }
917
918 void ActionSetCD(void *context)
919 {
920     (void)context;
921 }
922
923 OCStackResult BuildActionJSON(OCAction* action, unsigned char* bufferPtr,
924         uint16_t *remaining)
925 {
926     OCStackResult ret = OC_STACK_ERROR;
927     cJSON *json;
928     cJSON *body;
929
930     char *jsonStr;
931     uint16_t jsonLen;
932
933     OC_LOG(INFO, TAG, "Entering BuildActionJSON");
934     json = cJSON_CreateObject();
935
936     cJSON_AddItemToObject(json, "rep", body = cJSON_CreateObject());
937
938     OCCapability* pointerCapa = action->head;
939     while (pointerCapa)
940     {
941         cJSON_AddStringToObject(body, pointerCapa->capability,
942                 pointerCapa->status);
943         pointerCapa = pointerCapa->next;
944     }
945
946     jsonStr = cJSON_PrintUnformatted(json);
947
948     jsonLen = strlen(jsonStr);
949     if (jsonLen < *remaining)
950     {
951         strcat((char*) bufferPtr, jsonStr);
952         *remaining -= jsonLen;
953         bufferPtr += jsonLen;
954         ret = OC_STACK_OK;
955     }
956
957     cJSON_Delete(json);
958     free(jsonStr);
959
960     return ret;
961 }
962
963 OCPayload* BuildActionCBOR(OCAction* action)
964 {
965     OCRepPayload* payload = OCRepPayloadCreate();
966
967     if (!payload)
968     {
969         OC_LOG(INFO, TAG, "Failed to create put payload object");
970         return NULL;
971     }
972
973     OCCapability* pointerCapa = action->head;
974     while (pointerCapa)
975     {
976         OCRepPayloadSetPropString(payload, pointerCapa->capability, pointerCapa->status);
977         pointerCapa = pointerCapa->next;
978     }
979
980     return (OCPayload*) payload;
981 }
982
983 unsigned int GetNumOfTargetResource(OCAction *actionset)
984 {
985     int numOfResource = 0;
986
987     OCAction *pointerAction = actionset;
988
989     while (pointerAction != NULL)
990     {
991         numOfResource++;
992         pointerAction = pointerAction->next;
993     }
994
995     return numOfResource;
996 }
997
998 OCStackResult SendAction(OCDoHandle *handle, OCServerRequest* requestHandle, const char *targetUri,
999         OCPayload *payload)
1000 {
1001
1002     OCCallbackData cbData;
1003     cbData.cb = &ActionSetCB;
1004     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
1005     cbData.cd = NULL;
1006
1007     return OCDoResource(handle, OC_REST_PUT, targetUri, &requestHandle->devAddr,
1008                        payload, CT_ADAPTER_IP, OC_NA_QOS, &cbData, NULL, 0);
1009 }
1010
1011 OCStackResult DoAction(OCResource* resource, OCActionSet* actionset,
1012         OCServerRequest* requestHandle)
1013 {
1014     OCStackResult result = OC_STACK_ERROR;
1015
1016     if( NULL == actionset->head)
1017     {
1018         return result;
1019     }
1020
1021     OCAction *pointerAction = actionset->head;
1022
1023     while (pointerAction != NULL)
1024     {
1025         OCPayload* payload;
1026         payload = BuildActionCBOR(pointerAction);
1027
1028         if(payload == NULL)
1029         {
1030             return result;
1031         }
1032
1033         ClientRequestInfo *info = (ClientRequestInfo *) OICMalloc(
1034                 sizeof(ClientRequestInfo));
1035
1036         if( info == NULL )
1037         {
1038             OCFREE(payload);
1039             return OC_STACK_NO_MEMORY;
1040         }
1041
1042         memset(info, 0, sizeof(ClientRequestInfo));
1043
1044         info->collResource = resource;
1045         info->ehRequest = requestHandle;
1046
1047         result = SendAction(&info->required, info->ehRequest, pointerAction->resourceUri,
1048                 payload);
1049
1050         if (result != OC_STACK_OK)
1051         {
1052             OICFree(info);
1053             return result;
1054         }
1055
1056         AddClientRequestInfo(&clientRequstList, info);
1057
1058         pointerAction = pointerAction->next;
1059     }
1060
1061     return result;
1062 }
1063
1064 void DoScheduledGroupAction()
1065 {
1066     OC_LOG(INFO, TAG, "DoScheduledGroupAction Entering...");
1067     ScheduledResourceInfo* info = GetScheduledResource(scheduleResourceList);
1068
1069     if (info == NULL)
1070     {
1071         OC_LOG(INFO, TAG, "Target resource is NULL");
1072         goto exit;
1073     }
1074     else if (info->resource == NULL)
1075     {
1076         OC_LOG(INFO, TAG, "Target resource is NULL");
1077         goto exit;
1078     }
1079     else if (info->actionset == NULL)
1080     {
1081         OC_LOG(INFO, TAG, "Target ActionSet is NULL");
1082         goto exit;
1083     }
1084     else if (info->ehRequest == NULL)
1085     {
1086         OC_LOG(INFO, TAG, "Target ActionSet is NULL");
1087         goto exit;
1088     }
1089 #ifndef WITH_ARDUINO
1090     pthread_mutex_lock(&lock);
1091 #endif
1092     DoAction(info->resource, info->actionset, info->ehRequest);
1093 #ifndef WITH_ARDUINO
1094     pthread_mutex_unlock(&lock);
1095 #endif
1096
1097     if (info->actionset->type == RECURSIVE)
1098     {
1099         ScheduledResourceInfo *schedule;
1100         schedule = (ScheduledResourceInfo *) OICMalloc(
1101                 sizeof(ScheduledResourceInfo));
1102
1103         if (schedule)
1104         {
1105             OC_LOG(INFO, TAG, "Building New Call Info.");
1106             memset(schedule, 0, sizeof(ScheduledResourceInfo));
1107
1108             if (info->actionset->timesteps > 0)
1109             {
1110 #ifndef WITH_ARDUINO
1111                 pthread_mutex_lock(&lock);
1112 #endif
1113                 schedule->resource = info->resource;
1114                 schedule->actionset = info->actionset;
1115                 schedule->ehRequest = info->ehRequest;
1116
1117                 schedule->time = registerTimer(info->actionset->timesteps,
1118                         &schedule->timer_id,
1119                         &DoScheduledGroupAction);
1120
1121                 OC_LOG(INFO, TAG, "Reregisteration.");
1122 #ifndef WITH_ARDUINO
1123                 pthread_mutex_unlock(&lock);
1124 #endif
1125                 AddScheduledResource(&scheduleResourceList, schedule);
1126             }
1127             else
1128             {
1129                 OICFree(schedule);
1130             }
1131         }
1132     }
1133
1134     RemoveScheduledResource(&scheduleResourceList, info);
1135
1136     exit:
1137
1138     return;
1139 }
1140
1141 OCStackResult BuildCollectionGroupActionCBORResponse(
1142         OCMethod method/*OCEntityHandlerFlag flag*/, OCResource *resource,
1143         OCEntityHandlerRequest *ehRequest)
1144 {
1145     OCStackResult stackRet = OC_STACK_ERROR;
1146
1147     OC_LOG(INFO, TAG, "Group Action is requested.");
1148
1149     char *doWhat = NULL;
1150     char *details = NULL;
1151
1152     stackRet = ExtractKeyValueFromRequest(ehRequest, &doWhat, &details);
1153
1154     if(stackRet != OC_STACK_OK)
1155     {
1156         OC_LOG_V(ERROR, TAG, "ExtractKeyValueFromRequest failed: %d", stackRet);
1157         return stackRet;
1158     }
1159
1160     stackRet = OC_STACK_ERROR;
1161
1162     if (method == OC_REST_PUT)
1163     {
1164         OC_LOG(INFO, TAG, "Group Action[PUT].");
1165
1166         if (strcmp(doWhat, ACTIONSET) == 0)
1167         {
1168             OCActionSet *actionSet = NULL;
1169             stackRet = BuildActionSetFromString(&actionSet, details);
1170
1171             if(stackRet == OC_STACK_OK)
1172             {
1173                 if (actionSet != NULL)
1174                 {
1175                     stackRet = AddActionSet(&resource->actionsetHead,
1176                             actionSet);
1177                     if (stackRet == OC_STACK_ERROR)
1178                     {
1179                         if(actionSet != NULL)
1180                         {
1181                             DeleteActionSet( &actionSet );
1182                         }
1183                         OC_LOG(INFO, TAG, "Duplicated ActionSet ");
1184                     }
1185                 }
1186                 else
1187                 {
1188                     stackRet = OC_STACK_ERROR;
1189                     goto exit;
1190                 }
1191             }
1192             else
1193             {
1194                 stackRet = OC_STACK_ERROR;
1195             }
1196
1197         }
1198         else if (strcmp(doWhat, DELETE_ACTIONSET) == 0)
1199         {
1200             if (FindAndDeleteActionSet(&resource, details) == OC_STACK_OK)
1201             {
1202                 stackRet = OC_STACK_OK;
1203             }
1204             else
1205             {
1206                 stackRet = OC_STACK_ERROR;
1207             }
1208         }
1209
1210         OCRepPayload* payload = OCRepPayloadCreate();
1211
1212         if(!payload)
1213         {
1214             OC_LOG(ERROR, TAG, "Failed to allocate Payload");
1215             stackRet = OC_STACK_ERROR;
1216         }
1217         else
1218         {
1219             OCEntityHandlerResponse response = { 0 };
1220
1221             if(stackRet == OC_STACK_OK)
1222                 response.ehResult = OC_EH_OK;
1223             else
1224                 response.ehResult = OC_EH_ERROR;
1225
1226             // Format the response.  Note this requires some info about the request
1227             response.requestHandle = ehRequest->requestHandle;
1228             response.resourceHandle = ehRequest->resource;
1229             response.payload = (OCPayload*) payload;
1230             response.numSendVendorSpecificHeaderOptions = 0;
1231             memset(response.sendVendorSpecificHeaderOptions, 0,
1232                     sizeof response.sendVendorSpecificHeaderOptions);
1233             memset(response.resourceUri, 0, sizeof response. resourceUri);
1234             // Indicate that response is NOT in a persistent buffer
1235             response.persistentBufferFlag = 0;
1236             response.ehResult = (stackRet == OC_STACK_OK)?OC_EH_OK:OC_EH_ERROR;
1237
1238             // Send the response
1239             if (OCDoResponse(&response) != OC_STACK_OK)
1240             {
1241                 OC_LOG(ERROR, TAG, "Error sending response");
1242                 stackRet = OC_STACK_ERROR;
1243             }
1244         }
1245     }
1246     else if (method == OC_REST_POST)
1247     {
1248         OCActionSet *actionset = NULL;
1249
1250         OCRepPayload* payload = OCRepPayloadCreate();
1251         OCRepPayloadSetUri(payload, resource->uri);
1252
1253         if ((strcmp(doWhat, DO_ACTION) == 0)
1254                 || (strcmp(doWhat, "DoScheduledAction") == 0))
1255         {
1256             char *pActionsetName = NULL;
1257             long int delay = -1;
1258
1259             if (strcmp(doWhat, "DoScheduledAction") == 0)
1260             {
1261                 stackRet = ExtractActionSetNameAndDelaytime(details,
1262                         &pActionsetName, &delay);
1263
1264                 OCFREE(details)
1265                 details = pActionsetName;
1266             }
1267             else
1268             {
1269                 stackRet = OC_STACK_OK;
1270             }
1271
1272             if (stackRet == OC_STACK_OK)
1273             {
1274                 if (GetActionSet(details, resource->actionsetHead,
1275                         &actionset) != OC_STACK_OK)
1276                 {
1277                     OC_LOG(INFO, TAG, "ERROR");
1278                     stackRet = OC_STACK_ERROR;
1279                 }
1280
1281                 if (actionset == NULL)
1282                 {
1283                     OC_LOG(INFO, TAG, "Cannot Find ActionSet");
1284                     stackRet = OC_STACK_ERROR;
1285                 }
1286                 else
1287                 {
1288                     OC_LOG(INFO, TAG, "Group Action[POST].");
1289                     if (actionset->type == NONE)
1290                     {
1291                         OC_LOG_V(INFO, TAG, "Execute ActionSet : %s",
1292                                 actionset->actionsetName);
1293                         unsigned int num = GetNumOfTargetResource(
1294                                 actionset->head);
1295
1296                         ((OCServerRequest *) ehRequest->requestHandle)->ehResponseHandler =
1297                                 HandleAggregateResponse;
1298                         ((OCServerRequest *) ehRequest->requestHandle)->numResponses =
1299                                 num + 1;
1300
1301                         DoAction(resource, actionset,
1302                                 (OCServerRequest*) ehRequest->requestHandle);
1303                         stackRet = OC_STACK_OK;
1304                     }
1305                     else
1306                     {
1307                         OC_LOG_V(INFO, TAG, "Execute Scheduled ActionSet : %s",
1308                                 actionset->actionsetName);
1309
1310                         delay =
1311                                 (delay == -1 ? actionset->timesteps : delay);
1312
1313                         ScheduledResourceInfo *schedule;
1314                         schedule = (ScheduledResourceInfo *) OICMalloc(
1315                                 sizeof(ScheduledResourceInfo));
1316
1317                         if (schedule)
1318                         {
1319                             OC_LOG(INFO, TAG, "Building New Call Info.");
1320                             memset(schedule, 0,
1321                                     sizeof(ScheduledResourceInfo));
1322
1323                             schedule->resource = resource;
1324                             schedule->actionset = actionset;
1325                             schedule->ehRequest =
1326                                     (OCServerRequest*) ehRequest->requestHandle;
1327
1328                             if (delay > 0)
1329                             {
1330                                 OC_LOG_V(INFO, TAG, "delay_time is %lf seconds.",
1331                                         actionset->timesteps);
1332
1333                                 schedule->time = registerTimer(delay,
1334                                         &schedule->timer_id,
1335                                         &DoScheduledGroupAction);
1336
1337                                 AddScheduledResource(&scheduleResourceList,
1338                                         schedule);
1339                                 stackRet = OC_STACK_OK;
1340                             }
1341                             else
1342                             {
1343                                 stackRet = OC_STACK_ERROR;
1344                             }
1345
1346                             OICFree(schedule);
1347                         }
1348                     }
1349                 }
1350             }
1351         }
1352         else if (strcmp(doWhat, "CancelAction") == 0)
1353         {
1354             ScheduledResourceInfo *info =
1355                     GetScheduledResourceByActionSetName(scheduleResourceList, details);
1356
1357             if(info != NULL)
1358             {
1359                 unregisterTimer(info->timer_id);
1360
1361                 RemoveScheduledResource(&scheduleResourceList, info);
1362                 stackRet = OC_STACK_OK;
1363             }
1364             else
1365             {
1366                 stackRet = OC_STACK_ERROR;
1367             }
1368         }
1369
1370         else if (strcmp(doWhat, GET_ACTIONSET) == 0)
1371         {
1372             char *plainText = NULL;
1373             OCActionSet *actionset = NULL;
1374
1375             GetActionSet(details, resource->actionsetHead, &actionset);
1376             if (actionset != NULL)
1377             {
1378                 BuildStringFromActionSet(actionset, &plainText);
1379
1380                 if (plainText != NULL)
1381                 {
1382                     OCRepPayloadSetPropString(payload, ACTIONSET, plainText);
1383                 }
1384                 OICFree(plainText);
1385                 stackRet = OC_STACK_OK;
1386             }
1387         }
1388
1389         if(!payload)
1390         {
1391             OC_LOG(ERROR, TAG, "Failed to allocate Payload");
1392             stackRet = OC_STACK_ERROR;
1393         }
1394         else
1395         {
1396             OCEntityHandlerResponse response = { 0 };
1397             if(stackRet == OC_STACK_OK)
1398                 response.ehResult = OC_EH_OK;
1399             else
1400                 response.ehResult = OC_EH_ERROR;
1401
1402             // Format the response.  Note this requires some info about the request
1403             response.requestHandle = ehRequest->requestHandle;
1404             response.resourceHandle = ehRequest->resource;
1405             response.payload = (OCPayload*) payload;
1406             response.numSendVendorSpecificHeaderOptions = 0;
1407             memset(response.sendVendorSpecificHeaderOptions, 0,
1408                     sizeof response.sendVendorSpecificHeaderOptions);
1409             memset(response.resourceUri, 0, sizeof response.resourceUri);
1410             // Indicate that response is NOT in a persistent buffer
1411             response.persistentBufferFlag = 0;
1412             response.ehResult = (stackRet == OC_STACK_OK)?OC_EH_OK:OC_EH_ERROR;
1413
1414             // Send the response
1415             if (OCDoResponse(&response) != OC_STACK_OK)
1416             {
1417                 OC_LOG(ERROR, TAG, "Error sending response");
1418                 stackRet = OC_STACK_ERROR;
1419             }
1420         }
1421     }
1422
1423 exit:
1424
1425     OCFREE(doWhat)
1426     OCFREE(details)
1427
1428     return stackRet;
1429 }