root il y a 4 ans
commit
721846f4d6
16 fichiers modifiés avec 2997 ajouts et 0 suppressions
  1. BIN
      apple.png
  2. BIN
      apple_store.png
  3. 420 0
      clientarea.tpl
  4. 23 0
      composer.json
  5. BIN
      google_play.png
  6. 3 0
      index.php
  7. 29 0
      lang/english.php
  8. 29 0
      lang/german.php
  9. BIN
      linux.png
  10. BIN
      logo.png
  11. 158 0
      nextCloudEMailAvailable.php
  12. 125 0
      nextCloudUserAvailable.php
  13. 712 0
      nextcloud.php
  14. 1470 0
      nextcloud.php.old
  15. 28 0
      whmcs.json
  16. BIN
      windows.png

BIN
apple.png


BIN
apple_store.png


+ 420 - 0
clientarea.tpl

@@ -0,0 +1,420 @@
+{*
+ **********************************************************
+ * Developed by: Team Theme Metro
+ * Website: http://www.thememetro.com
+ * Customized ny thurdata
+ **********************************************************
+*}
+{if $modulechangepwresult}
+  {if $modulechangepwresult == "success"}
+    {include file="$template/includes/alert.tpl" type="success" msg=$modulechangepasswordmessage textcenter=true}
+  {elseif $modulechangepwresult == "error"}
+    {include file="$template/includes/alert.tpl" type="error" msg=$modulechangepasswordmessage|strip_tags textcenter=true}
+  {/if}
+{/if}
+
+{if $modulecustombuttonresult}
+  {if $modulecustombuttonresult == "success"}
+    {include file="$template/includes/alert.tpl" type="success" msg=$LANG.moduleactionsuccess textcenter=true idname="alertModuleCustomButtonSuccess"}
+  {else}
+    {include file="$template/includes/alert.tpl" type="error" msg=$LANG.moduleactionfailed|cat:' ':$modulecustombuttonresult textcenter=true idname="alertModuleCustomButtonFailed"}
+  {/if}
+{/if}
+{if $pendingcancellation}
+    {include file="$template/includes/alert.tpl" type="error" msg=$LANG.cancellationrequestedexplanation textcenter=true idname="alertPendingCancellation"}
+{/if}
+{if $unpaidInvoice}
+  <div class="alert alert-{if $unpaidInvoiceOverdue}danger{else}warning{/if}" id="alert{if $unpaidInvoiceOverdue}Overdue{else}Unpaid{/if}Invoice">
+    <div class="pull-right">
+      <a href="viewinvoice.php?id={$unpaidInvoice}" class="btn btn-xs btn-default">
+        {lang key='payInvoice'}
+      </a>
+    </div>
+    {$unpaidInvoiceMessage}
+  </div>
+{/if}
+<div class="tab-content margin-bottom">
+  <div class="tab-pane fade show active" id="tabOverview">
+    {if $tplOverviewTabOutput}
+			{$tplOverviewTabOutput}
+    {else}
+      <div class="section">
+        <div class="product-details">
+          <div class="row row-eq-height row-eq-height-sm">
+            <div class="col-md-6">
+              <div class="product-holder product-status-{$rawstatus|strtolower}" style="min-height: unset; height:210px">
+                <div class="product-content">
+                  <div class="product-image">
+                    <div class="feature-icon">
+                      {if $moduleParams.configoption3 == 'on'}
+                        <img src="/templates/croster/thurdata/productgroups/3.svg" class="img-fluid" style="height:100px;">
+                      {else}
+                        <img src="/templates/croster/thurdata/productgroups/3.svg" class="img-fluid" style="height:100px;">
+                      {/if}
+                    </div>
+                  </div>
+                  <h4><small>{$groupname}</small> - {$product}</h4>
+                  <div class="status-sticker-wrapper">
+                    <div class="status-sticker product-status-{$rawstatus|strtolower}">
+                      {$status}
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+            <div class="col-md-6">
+              <div class="product-info" style="min-height: unset; height:210px;">
+                <table width="100%" border="0">
+            	    <tr>
+            		<td class="list-heading" style="font-size: 85%;">{$LANG.clientareahostingregdate}</td>
+            		<td class="list-text"  style="font-size: 85%;">{$regdate}</td>
+            	    </tr>
+            	    {if $billingcycle != 'Gratis-Account'}
+            		<tr>
+            		    <td class="list-heading" style="font-size: 85%;">{$LANG.firstpaymentamount}</td>
+            		    <td class="list-text"  style="font-size: 85%;">{$firstpaymentamount}</td>
+            		</tr>
+            		<tr>
+            		    <td class="list-heading" style="font-size: 85%;">{$LANG.recurringamount}</td>
+            		    <td class="list-text"  style="font-size: 85%;">{$recurringamount}</td>
+            		</tr>
+            		<tr>
+            		    <td class="list-heading" style="font-size: 85%;">{$LANG.orderbillingcycle}</td>
+            		    <td class="list-text"  style="font-size: 85%;">{$billingcycle}</td>
+            		</tr>
+			<tr>
+			    <td class="list-heading" style="font-size: 85%;">{$LANG.clientareahostingnextduedate}</td>
+			    <td class="list-text"  style="font-size: 85%;">{$nextduedate}</td>
+			</tr>
+			<tr>
+			    <td class="list-heading" style="font-size: 85%;">{$LANG.orderpaymentmethod}</td>
+			    <td class="list-text"  style="font-size: 85%;">{$paymentmethod}</td>
+			</tr>
+                  {else}
+                	<tr>
+                	    <td class="list-heading" style="font-size: 85%;"><strong>Trial Account</strong></td>
+            	    	    {if ($smarty.now - ($regdate|@strtotime)) > 950400} {* wenn Heute - RegisterDatum > 11 Tage *}
+                    		<td class="list-text" style="color:yellow;font-size:85%;">Endet in {(14 - (($smarty.now - ($regdate|@strtotime)) / 86400)|round)} Tagen</td>
+                    	    {elseif ($smarty.now - ($regdate|@strtotime)) > 1123200} {* wenn Heute - RegisterDatum > 13 Tage *}
+                    		<td class="list-text" style="color:red;font-size:85%;">Letzter Tag der Trial Periode</td>
+                    	    {else}
+                    		<td class="list-text" style="font-size: 85%;">Endet in {(14 - (($smarty.now - ($regdate|@strtotime)) / 86400)|round)} Tagen</td>
+                    	    {/if}
+            		</tr>
+            		<tr>
+                	    <td colspan="2"><br /><br /></td>
+                	</tr>
+            		<tr>
+            		    <td></td>
+            		    <td><a href="/upgrade.php?type=package&id={$id}" class="btn btn-block btn-primary">Jetzt upgraden</a></td>
+            		</tr>
+                  {/if}
+		</table> 
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      {*
+        {if $showcancelbutton || $packagesupgrade}
+          <div class="row">
+            {if $packagesupgrade}
+              <div class="col-xs-{if $showcancelbutton}6{else}12{/if}">
+                <a href="upgrade.php?type=package&amp;id={$id}" class="btn btn-block btn-primary">{$LANG.upgrade}</a>
+              </div>
+            {/if}
+            {if $showcancelbutton}
+              <div class="col-xs-{if $packagesupgrade}6{else}12{/if}">
+                <a href="clientarea.php?action=cancel&amp;id={$id}" class="btn btn-block btn-danger {if $pendingcancellation}disabled{/if}">{if $pendingcancellation}{$LANG.cancellationrequested}{else}{$LANG.clientareacancelrequestbutton}{/if}</a>
+              </div>
+            {/if}
+          </div>
+        {/if}
+      *}
+      {if $systemStatus == 'Active'}
+        {foreach $hookOutput as $output}
+          <div class="section">
+            <div>
+              {$output}
+            </div>
+            <div class=" clearfix"></div>
+          </div>
+        {/foreach}
+        {if $domain || $moduleclientarea || $configurableoptions || $customfields || $lastupdate}
+          <div class="section">
+            <div class="card panel panel-tabs">
+              <div class="card-header">
+                <ul class="nav nav-pills card-header-pills flex-column flex-md-row">
+                  {if $domain}
+                    <li class="nav-item">
+                      <a href="#domain" data-toggle="tab" class="nav-link active"><i class="fas fa-globe fa-fw"></i> {if $type eq "server"}{lang key='sslserverinfo'}{elseif ($type eq "hostingaccount" || $type eq "reselleraccount") && $serverdata}{lang key='hostingInfo'}{else}{lang key='clientareahostingdomain'}{/if}</a>
+                    </li>
+                  {elseif $moduleclientarea}
+                    <li class="nav-item">
+                      <a href="#manage" data-toggle="tab" class="nav-link active"><i class="fas fa-globe fa-fw"></i> {lang key='manage'}</a>
+                    </li>
+                  {/if}
+                  {if $configurableoptions}
+                    <li class="nav-item">
+                      <a href="#configoptions" data-toggle="tab" class="nav-link{if !$domain && !$moduleclientarea} active{/if}"><i class="fas fa-cubes fa-fw"></i>Details</a>
+                    </li>
+                  {/if}
+                  {if $metricStats}
+                    <li class="nav-item">
+                      <a href="#metrics" data-toggle="tab" class="nav-link{if !$domain && !$moduleclientarea && !$configurableoptions} active{/if}"><i class="fas fa-chart-line fa-fw"></i> {lang key='metrics.title'}</a>
+                    </li>
+                  {/if}
+                  {if $customfields}
+                    <li class="nav-item">
+                      <a href="#additionalinfo" data-toggle="tab" class="nav-link{if !$domain && !$moduleclientarea && !$metricStats && !$configurableoptions} active{/if}"><i class="fas fa-info fa-fw"></i>Zugangsdaten</a>
+                    </li>
+                  {/if}
+                  {if $lastupdate}
+                    <li class="nav-item">
+                      <a href="#resourceusage" data-toggle="tab" class="nav-link{if !$domain && !$moduleclientarea && !$configurableoptions && !$customfields} active{/if}"><i class="fas fa-inbox fa-fw"></i> {lang key='resourceUsage'}</a>
+                    </li>
+                  {/if}
+                </ul>
+              </div>
+              <div class="card-body">
+                <div class="tab-content">
+                  {if $configurableoptions}
+                    <div class="tab-pane fade{if !$domain && !$moduleclientarea} show active{/if}" role="tabpanel" id="configoptions">
+                      <table width="100%" cellspacing="0" cellpadding="0" class="frame">
+                        <tr>
+                          <td>
+                            <table width="100%" border="0" cellpadding="10" cellspacing="0" class="table table-striped table-framed">
+                              <tr>
+                                <td align='left'>Benutzername</td>
+                                <td align="left">{$mailaddress}</td>
+                              </tr>
+                              <tr>
+                                <td align='left'>Nextcloud Speicher inklusive</td>
+                                <td align="left">{$basequota} GB</td>
+                              </tr>
+                              <tr>
+                                <td align='left'>Nextcloud Speicher zugebucht</td>
+                                <td align="left">{$addonquota} GB</td>
+                              </tr>
+                              <tr>
+                                <td align='left'>Nextcloud Speicher gesamt</td>
+                                <td align="left">{$userquota} GB</td>
+                              </tr>
+                              {if $moduleParams.configoption3 == 'on'}
+                              <tr>
+                                <td align='left'>NextCloud Speicher</td>
+                                <td align="left">{$userquota * 2} GB</a></td>
+                              </tr>
+                              {/if}
+                            </table>
+                          </td>
+                        </tr>
+                      </table>
+                    </div>
+                  {/if}
+                  {if $metricStats}
+                    <div class="tab-pane fade{if !$domain && !$moduleclientarea && !$configurableoptions} show active{/if}" role="tabpanel" id="metrics">
+                      {include file="$template/clientareaproductusagebilling.tpl"}
+                    </div>
+                  {/if}
+                  {if $customfields}
+                    <div class="tab-pane fade{if !$domain && !$moduleclientarea && !$configurableoptions && !$metricStats} show active{/if}" role="tabpanel" id="additionalinfo">
+                      <table width="100%" cellspacing="0" cellpadding="0" class="frame">
+                        <tr>
+                          <td align='left'>NextCloud URL</td>
+                          <td align="left"><a href="{$webmailurl}" target="_blank">{$webmailurl}</a></td>
+                        </tr>
+                        {if $moduleParams.configoption3 == 'on'}
+                        <tr>
+                          <td align='left'>NextCloud URL</td>
+                          <td align="left"><a href="{$moduleParams.configoption4}" target="_blank">{$moduleParams.configoption4}</a></td>
+                        </tr>
+                        {/if}
+                        <tr>
+                          <td colspan=2 align='left'>
+                            <br />
+                            <hr>
+                            <br />
+                          </td>
+                        <tr>
+                          <td colspan=2 align='left'>
+                            <h6 class="heading">Integrieren Sie Ihr Nextcloud auf Ihr Mobiltelefon oder Ihren PC</h6>
+                          </td>
+                        </tr>
+                        <tr>
+                          <td colspan=2 align='left'>
+                            <h6 class="heading">Als Benutzernamen verwenden Sie immer Ihre Nextcloud Account ({$mailaddress})</h6>
+                          </td>
+                        </tr>
+                        <tr>
+                          <td colspan=2 align='left'>
+                            <br />
+                            <hr>
+                            <br />
+                          </td>
+                        </tr>
+                        <tr>
+                          <td align='center'>
+                        	<strong>Windows Client</strong><br />
+                        	Synchronisierung Ihrer Dateien mit Nextcloud<br />
+                        	Mehrere Konten auf veschiedenen Servern<br />
+                        	<br />
+                        	<a href="https://github.com/nextcloud/desktop/releases/download/v3.2.4/Nextcloud-3.2.4-x64.msi" target="_blank"><img src="modules/servers/nextcloud/windows.png" /><a/>
+                          </td>
+                          <td align="center">
+                        	<strong>Mac Client</strong><br />
+                        	Synchronisierung Ihrer Dateien mit Nextcloud<br />
+                        	Mehrere Konten auf veschiedenen Servern<br />
+                        	<br />
+                        	<a href="https://github.com/nextcloud/desktop/releases/download/v3.2.4/Nextcloud-3.2.4.pkg" target="_blank"><img src="modules/servers/nextcloud/apple.png" /><a/>
+                          </td>
+                        </tr>
+                          <td colspan=2 align='left'>
+                            <br />
+                            <hr>
+                            <br />
+                          </td>
+                        </tr>
+                        <tr>
+                          <td align='center'>
+                        	<strong>Linux Client</strong><br />
+                        	Synchronisierung Ihrer Dateien mit Nextcloud<br />
+                        	Mehrere Konten auf veschiedenen Servern<br />
+                        	<br />
+                                <a href="https://github.com/nextcloud/desktop/releases/download/v3.2.4/Nextcloud-3.2.4-x86_64.AppImage" target="_blank"><img src="modules/servers/nextcloud/linux.png" /><a/>
+                          </td>
+                          <td align="center"><strong>Appimage</strong><br />
+                        	Der Linux-Client liegt im Appimage Format vor<br />
+                        	Das AppImage Format ist eine neue Methode Linux Applikationen zu packen.<br />
+                        	AppImages sind portabel, das heisst sie müssen nicht installiert <br />
+                        	werden und funktionieren mit nahezu jeder Linux Distribution.<br />
+                        	Alle Abhängigkeiten befinden sich in der AppImage Datei.<br />
+                          </td>
+                        </tr>
+                          <td colspan=2 align='left'>
+                            <br />
+                            <hr>
+                            <br />
+                          </td>
+                        </tr>
+                        <tr>
+                          <td align='center'>
+                        	<strong>App für Android</strong><br />
+                        	Mit dem Nextcloud-Client für Android<br />
+                        	können Sie Ihre Dateien über eine <br />
+                        	verschlüsselte Verbindung völlig <br />
+                        	sicher synchronisieren, bearbeiten und teilen.<br />
+                        	<br />
+                                <a href="https://apps.apple.com/ch/app/nextcloud/id1125420102" target="_blank"><img src="modules/servers/nextcloud/apple_store.png" /><a/>
+                          </td>
+                          <td align="center">
+                        	<strong>App für iPhone</strong><br />
+                        	Mit dem Nextcloud-Client für iPhone<br />
+                        	können Sie Ihre Dateien über eine <br />
+                        	verschlüsselte Verbindung völlig <br />
+                        	sicher synchronisieren, bearbeiten und teilen.<br />
+                        	<br />
+                                <a href="https://play.google.com/store/apps/details?id=com.nextcloud.client&hl=de_CH&gl=US" target="_blank"><img src="modules/servers/nextcloud/google_play.png" /><a/>
+                          </td>
+                        </tr>
+                      </table>
+                    </div>
+                  {/if}
+                  {if $lastupdate}
+                    <div class="tab-pane fade" role="tabpanel" id="resourceusage" align="center">
+                      <div class="col-sm-10">
+                        <div class="col-sm-6">
+                          <h4>{lang key='diskSpace'}</h4>
+                          <input type="text" value="{$diskpercent|substr:0:-1}" class="dial-usage" data-width="100" data-height="100" data-min="0" data-readOnly="true" />
+                          <p>{($diskusage / 1024)|round:1} GB / {($disklimit / 1024)|round:1} GB</p>
+                        </div>
+                      </div>
+                      <div class="clearfix">
+                      </div>
+                      <p class="text-muted">{lang key='clientarealastupdated'}: {$lastupdate}</p>
+                      <script src="{$BASE_PATH_JS}/jquery.knob.js"></script>
+                      <script>
+                        jQuery(function() {
+                          jQuery(".dial-usage").knob({
+                            'format': function(v) {
+                              alert(v);
+                            }
+                          });
+                        });
+                      </script>
+                      <div class="col-xs-{if $showcancelbutton}6{else}12{/if}">
+                        <a href="upgrade.php?type=configoptions&amp;id={$id}" class="btn btn-block btn-primary">Weiteren Speicher hinzubuchen</a>
+                      </div>
+                    </div>
+                  {/if}
+                </div>
+              </div>
+            </div>
+          </div>
+        {/if}
+        {else}
+        <div class="alert-lg no-data">
+          <div class="icon">
+            <i class="fas fa-exclamation-triangle"></i>
+          </div>
+          <div class="text">
+            {if $suspendreason}
+              <strong>{$suspendreason}</strong><br />
+            {/if}
+            {$LANG.cPanel.packageNotActive} {$status}.<br />
+            {if $systemStatus eq "Pending"}
+              {$LANG.cPanel.statusPendingNotice}
+            {elseif $systemStatus eq "Suspended"}
+              {$LANG.cPanel.statusSuspendedNotice}
+            {/if}
+          </div>
+        </div>
+      {/if}
+    {/if}
+  </div>
+  <div class="tab-pane fade in" id="tabChangepw">
+  <div class="section">
+    <div class="section-header">
+      <h3>{$LANG.serverchangepassword}</h3>
+      <p class="desc">Hier können Sie Ihr Passwort für {$mailaddress} ändern</p>
+    </div>
+    <div class="section-body">
+      <div class="row">
+        <div class="col-sm-7">
+          <form class=" using-password-strength" method="post" action="{$smarty.server.PHP_SELF}?action=productdetails&id={$id}" role="form">
+            <input type="hidden" name="id" value="{$id}" />
+            <input type="hidden" name="modulechangepassword" value="true" />
+            <div class="TM-card">
+              <div id="newPassword1" class="form-group has-feedback">
+                <label for="inputNewPassword1" class="control-label">{$LANG.newpassword}</label>
+                <input type="password" class="form-control" id="inputNewPassword1" name="newpw" autocomplete="off" />
+                <span class="form-control-feedback glyphicon"></span>
+                {include file="$template/thurdata/thurpwcheck.tpl"}
+              </div>
+              <div class="alert alert-info">
+                  <div id='hints'>
+                      <strong id='hint2Head'></strong>
+                      <div id='hintLength'></div>
+                      <div id='hintNumeric'></div>
+                      <div id='hintSymbols'></div>
+                      <div id='hintUpperLower'></div>
+                  </div>
+              </div>
+              <div id="newPassword2" class="form-group has-feedback">
+                <label for="inputNewPassword2" class="control-label">{$LANG.confirmnewpassword}</label>
+                <input type="password" class="form-control" id="inputNewPassword2" name="confirmpw" autocomplete="off" />
+                <span class="form-control-feedback glyphicon"></span>
+                <div id="inputNewPassword2Msg">
+                </div>
+              </div>
+            </div>
+            <div class="form-actions">
+              <input class="btn btn-primary" type="submit" value="{$LANG.clientareasavechanges}" />
+            </div>
+          </form>
+        </div>
+      </div>
+    </div>
+  </div>
+  </div>
+</div>

+ 23 - 0
composer.json

@@ -0,0 +1,23 @@
+{
+    "name": "Thurdata/Nextcloud",
+    "description": "Nextcloud Provisioing Module",
+    "version": "2.0.0",
+    "type": "project",
+    "license": "EULA",
+    "homepage": "http://www.thurdata.ch",
+    "support":
+            {
+                "email": "info@thurdata.ch",
+                "issues": "http://support.thurdata.ch",
+                "forum": "http://forum.thurdata.ch"
+            },
+    "authors": [
+	{
+	    "name": "Roland Käser / Andre Genrich"
+	}
+    ],
+    "require":
+            {
+                "php": ">=7.1.0"
+            }
+}

BIN
google_play.png


+ 3 - 0
index.php

@@ -0,0 +1,3 @@
+<?php 
+	header('location: ../../../index.php');die();
+?>

+ 29 - 0
lang/english.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * WHMCS Language File
+ * English (en)
+ *
+ * Please Note: These language files are overwritten during software updates
+ * and therefore editing of these files directly is not advised. Instead we
+ * recommend that you use overrides to customise the text displayed in a way
+ * which will be safely preserved through the upgrade process.
+ * 
+ *
+ * @package    WHMCS
+ * @author     WHMCS Limited <development@whmcs.com>
+ * @copyright  Copyright (c) WHMCS Limited 2005-2015
+ * @license    http://www.whmcs.com/license/ WHMCS Eula
+ * @version    $Id$
+ * @link       http://www.whmcs.com/
+ */
+
+if (!defined("WHMCS")) die("This file cannot be accessed directly");
+
+
+$lang['NextcloudSettings'] = "Nextcloud Settings";
+$lang['EmailAddress'] = "Email Address";
+$lang['ChangenextcloudEmailAddress'] = "Change NextCloud Email Address";
+$lang['nextcloudEmailAddress'] = "NextCloud Email Address";
+$lang['suser'] = "Benutzername";
+$lang['surl'] =  "NextCloud Login URL";
+$lang['sclients'] =  "NextCloud Clients";

+ 29 - 0
lang/german.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * WHMCS Language File
+ * English (en)
+ *
+ * Please Note: These language files are overwritten during software updates
+ * and therefore editing of these files directly is not advised. Instead we
+ * recommend that you use overrides to customise the text displayed in a way
+ * which will be safely preserved through the upgrade process.
+ * 
+ *
+ * @package    WHMCS
+ * @author     WHMCS Limited <development@whmcs.com>
+ * @copyright  Copyright (c) WHMCS Limited 2005-2015
+ * @license    http://www.whmcs.com/license/ WHMCS Eula
+ * @version    $Id$
+ * @link       http://www.whmcs.com/
+ */
+
+if (!defined("WHMCS")) die("This file cannot be accessed directly");
+
+
+$lang['NextcloudSettings'] = "Nextcloud Einstellungen";
+$lang['EmailAddress'] = "Email Adresse";
+$lang['ChangenextcloudEmailAddress'] = "NextCloud Email Adresse ändern";
+$lang['nextcloudEmailAddress'] = "NextCloud Email Adresse";
+$lang['suser'] = "Benutzername";
+$lang['surl'] = "NextCloud Login URL";
+$lang['sclients'] = "NextCloud Clients";

BIN
linux.png


BIN
logo.png


+ 158 - 0
nextCloudEMailAvailable.php

@@ -0,0 +1,158 @@
+<?php
+/**
+ *
+ * 
+ * @see https://www.zimbra.com
+ * @copyright Copyright (c) Thurdata GmbH 2020
+ * @license GPL
+ * 
+ */
+$pos = strpos($_SERVER['HTTP_REFERER'],getenv('HTTP_HOST'));
+if($pos===false) {
+    die('Restricted access');
+}
+
+/**
+ * Requires the whmcs init
+ * Requires this PHP api to make soap calls and parse responses
+ */
+require_once(__DIR__ . '/../../../init.php');
+use WHMCS\Database\Capsule;
+
+$whmcs = App::self();
+$email = $_GET['email'];
+if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
+    echo "invalid";
+    exit;
+}
+$parts = explode("@",$email); 
+$domain = $parts[1];
+
+if (strcasecmp($domain,"seecure.ch") {
+    echo "no";
+    exit;
+}
+if (strcasecmp($domain,"seemail.ch") {
+    echo "no";
+    exit;
+}
+if (strcasecmp($domain,"thurmail.ch") {
+    echo "no";
+    exit;
+}
+if (strcasecmp($domain,"thurbit.ch") {
+    echo "no";
+    exit;
+}
+
+
+
+$productID = $_GET['pid'];
+
+$accessData = array('nextcloudServer' => '', 'adminUser' => '', 'adminPass' => '');
+
+$serverGroupIDObj = Capsule::table('tblproducts')
+	->select('servergroup')
+	->where('id', '=', $productID)
+	->get();
+$serverGroupID = $serverGroupIDObj[0]->servergroup;
+
+$serverIDObj = Capsule::table('tblservergroupsrel')
+    ->select('serverid')
+    ->where('groupid', '=', $serverGroupID)
+    ->get();
+$serverID = $serverIDObj[0]->serverid;
+
+$server = Capsule::table('tblservers')
+	->select('hostname', 'username', 'password')
+	->where('id', '=', $serverID)
+	->where('active', '=', 1)
+	->get();
+$accessData['nextcloudServer'] = $server[0]->hostname;
+$accessData['adminUser'] = $server[0]->username;
+$adminPassDecrypt = localAPI('DecryptPassword', array('password2' => $server[0]->password));
+
+if ($adminPassDecrypt['result'] == 'success') {
+    $accessData['adminPass'] = $adminPassDecrypt['password'];
+}
+
+
+//error_log("NextCloud User Avaialable: ACC    " . $accountName);
+//error_log("--------------------------");
+//error_log("NextCloud User Avaialable: PID    " . $productID);
+//error_log("NextCloud User Avaialable: GID    " . $serverGroupID);
+//error_log("NextCloud User Avaialable: SID    " . $serverID);
+//error_log("NextCloud User Avaialable: SERVER " . $accessData['nextcloudServer']);
+//error_log("NextCloud User Avaialable: USER   " . $accessData['adminUser']);
+//error_log("NextCloud User Avaialable: PASS   " . $accessData['adminPass']);
+
+
+$nextcloudURL =  'https://' . $accessData['nextcloudServer'] . "/ocs/v1.php/cloud/users?search=" . $email;
+
+//error_log("NextCloud User Avaialable: URL    " . $nextcloudURL);
+
+$response = nextcloud_send($nextcloudURL,$accessData['adminUser'],$accessData['adminPass'],"GET");
+
+//error_log("NextCloud User Available NextCloud Response: " . $response->ocs->meta->statuscode);
+//error_log("NextCloud User Available NextCloud Response Content " . print_r($response,true));
+
+if (is_null($response) == true) {
+    echo "error";
+    exit;
+}
+
+if ($response->ocs->meta->statuscode != '100') {
+    echo "no";
+} else { 
+    if (count($response->ocs->data->users) > 0) {
+	echo "no";
+	exit;
+    } else {
+        echo "yes";
+        exit;
+    }
+}
+
+
+
+
+
+
+function nextcloud_send($href, $username, $password, $action, $post = array()) {
+    $postdata = http_build_query($post);
+    $ch = curl_init();
+
+    if (strtoupper($action) == 'GET') {
+        curl_setopt($ch, CURLOPT_HTTPGET, true);
+    }
+
+    curl_setopt($ch, CURLOPT_URL, $href);
+    curl_setopt($ch, CURLOPT_USERPWD, $username . ":" . $password);
+    curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/json","OCS-APIRequest: true",'content-type: application/x-www-form-urlencoded'));
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
+    $result_json = curl_exec($ch);
+    $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+    curl_close($ch);
+
+    if ($httpcode >= 200 && $httpcode < 300) {
+        //print_r($result_json);die();
+	$result_bom = nextcloud_remove_utf8bom($result_json);
+	$result = json_decode($result_bom);
+	return($result);
+    } else {
+	return null;
+    }
+}
+
+function nextcloud_remove_utf8bom($text) {
+    $bom = pack('H*', 'EFBBBF');
+    $text = preg_replace("/^$bom/", '', $text);
+    return $text;
+}
+
+

+ 125 - 0
nextCloudUserAvailable.php

@@ -0,0 +1,125 @@
+<?php
+/**
+ * Helper script to check the availibility of a Zimbra mailbox useable with ajax requests
+ * 
+ * @see https://www.zimbra.com
+ * @copyright Copyright (c) Thurdata GmbH 2020
+ * @license GPL
+ * 
+ */
+$pos = strpos($_SERVER['HTTP_REFERER'],getenv('HTTP_HOST'));
+if($pos===false) {
+    die('Restricted access');
+}
+
+/**
+ * Requires the whmcs init
+ * Requires this PHP api to make soap calls and parse responses
+ */
+require_once(__DIR__ . '/../../../init.php');
+use WHMCS\Database\Capsule;
+
+$whmcs = App::self();
+$accountName = $_GET['name'];
+if(!preg_match('/^[a-zA-Z0-9\-]+$/', $accountName)) {
+    echo "invalid";
+    exit;
+}
+$productID = $_GET['pid'];
+
+$accessData = array('zimbraServer' => '', 'adminUser' => '', 'adminPass' => '');
+
+$serverGroupIDObj = Capsule::table('tblproducts')
+	->select('servergroup')
+	->where('id', '=', $productID)
+	->get();
+$serverGroupID = $serverGroupIDObj[0]->servergroup;
+
+$serverIDObj = Capsule::table('tblservergroupsrel')
+    ->select('serverid')
+    ->where('groupid', '=', $serverGroupID)
+    ->get();
+$serverID = $serverIDObj[0]->serverid;
+
+$server = Capsule::table('tblservers')
+	->select('hostname', 'username', 'password')
+	->where('id', '=', $serverID)
+	->where('active', '=', 1)
+	->get();
+$accessData['nextcloudServer'] = $server[0]->hostname;
+$accessData['adminUser'] = $server[0]->username;
+$adminPassDecrypt = localAPI('DecryptPassword', array('password2' => $server[0]->password));
+
+if ($adminPassDecrypt['result'] == 'success') {
+    $accessData['adminPass'] = $adminPassDecrypt['password'];
+}
+
+
+//error_log("NextCloud User Avaialable: ACC    " . $accountName);
+//error_log("--------------------------");
+//error_log("NextCloud User Avaialable: PID    " . $productID);
+//error_log("NextCloud User Avaialable: GID    " . $serverGroupID);
+//error_log("NextCloud User Avaialable: SID    " . $serverID);
+//error_log("NextCloud User Avaialable: SERVER " . $accessData['nextcloudServer']);
+//error_log("NextCloud User Avaialable: USER   " . $accessData['adminUser']);
+//error_log("NextCloud User Avaialable: PASS   " . $accessData['adminPass']);
+
+
+$nextcloudURL =  'https://' . $accessData['nextcloudServer'] . "/ocs/v1.php/cloud/users/" . $accountName;
+error_log("NextCloud User Avaialable: URL    " . $nextcloudURL);
+
+$response = nextcloud_send($nextcloudURL,$accessData['adminUser'],$accessData['adminPass'],"GET");
+
+error_log("NextCloud User Available NextCloud Response: " . $response->ocs->meta->statuscode);
+error_log("NextCloud User Available NextCloud Response Content " . print_r($response,true));
+
+if (is_null($response) == true) {
+    echo "error";
+}
+
+if ($response->ocs->meta->statuscode == '100') {
+    echo "no";
+} else {
+    echo "yes";
+}
+
+
+
+function nextcloud_send($href, $username, $password, $action, $post = array()) {
+    $postdata = http_build_query($post);
+    $ch = curl_init();
+
+    if (strtoupper($action) == 'GET') {
+        curl_setopt($ch, CURLOPT_HTTPGET, true);
+    }
+
+    curl_setopt($ch, CURLOPT_URL, $href);
+    curl_setopt($ch, CURLOPT_USERPWD, $username . ":" . $password);
+    curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/json","OCS-APIRequest: true",'content-type: application/x-www-form-urlencoded'));
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
+    $result_json = curl_exec($ch);
+    $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+    curl_close($ch);
+
+    if ($httpcode >= 200 && $httpcode < 300) {
+        //print_r($result_json);die();
+	$result_bom = nextcloud_remove_utf8bom($result_json);
+	$result = json_decode($result_bom);
+	return($result);
+    } else {
+	return null;
+    }
+}
+
+function nextcloud_remove_utf8bom($text) {
+    $bom = pack('H*', 'EFBBBF');
+    $text = preg_replace("/^$bom/", '', $text);
+    return $text;
+}
+
+

+ 712 - 0
nextcloud.php

@@ -0,0 +1,712 @@
+<?php
+/**
+ * WHMCS Seafile Provisioning Module
+ *
+ * Provisioning for User Account on the Seafile Server
+ *
+ * @see https://www.seafile.com
+ * @copyright Copyright (c) Thurdata GmbH 2020
+ * @license GPL
+ */
+use WHMCS\Database\Capsule;
+
+if (!defined('WHMCS')) {
+	die('This file cannot be accessed directly'); }
+
+
+function nextcloud_MetaData() {
+    return array(
+            'DisplayName' => 'Nextcloud Provisioning',
+            'APIVersion' => '1.2',
+            'DefaultNonSSLPort' => '80',
+            'DefaultSSLPort' => '443',
+            'RequiresServer' => true,
+            'ServiceSingleSignOnLabel' => 'Login to Nextcloud',
+            'AdminSingleSignOnLabel' => 'Login to Nextcloud Admin',
+            'ListAccountsUniqueIdentifierDisplayName' => 'Domain',
+            'ListAccountsUniqueIdentifierField' => 'domain',
+            'ListAccountsProductField' => 'configoption1',
+    );
+}
+
+/**
+ * Define SeaFile product configuration options. 
+ *
+ * @see https://developers.whmcs.com/provisioning-modules/config-options/
+ *
+ * @return array
+ */
+function nextcloud_ConfigOptions() {
+	$configarray = array(	 
+	    'quota' => array(
+			'Type' => 'text',
+			'Description' => 'Basis  User-Quota für dieses Produkt in GB',
+			'Default' => '10',
+			'Size' => '15',
+			'FriendlyName' => 'User Quota',
+		),
+	);
+	return $configarray;
+}
+
+/**
+ * Test connection to a Nextcloud server with the given server parameters.
+ *
+ * Allows an admin user to verify that an API connection can be
+ * successfully made with the given configuration parameters for a
+ * server.
+ *
+ * When defined in a module, a Test Connection button will appear
+ * alongside the Server Type dropdown when adding or editing an
+ * existing server.
+ *
+ * @param array $params common module parameters
+ *
+ * @see https://developers.whmcs.com/provisioning-modules/module-parameters/
+ *
+ * @return array
+ */
+function nextcloud_TestConnection($params) {
+	error_log("Nextcloud TestConnection: " . $params['serverhttpprefix'] . '://' . $params['serverhostname'] . ':' . $params['serverport']);
+	$nextcloudURL = $params['serverhttpprefix'] . '://' . $params['serverhostname'] . ':' . $params['serverport'] . "/ocs/v1.php/cloud/capabilities";
+	$response = nextcloud_send($nextcloudURL,$params['serverusername'],$params['serverpassword'],"GET");
+	
+	if ($response === false) {
+	    return array(
+		'success' => false,
+		'error' => 'Error: cannot communicate with server ' . $nextcloudURL,
+	    );
+	}
+	
+	if ($response->ocs->meta->status == 'ok') {
+		return array(
+		'success' => true,
+		'error' => '',
+	    );
+	} else {
+	    if (isset($response->ocs->meta->message)) {
+		logModuleCall(
+			'nextcloud',
+			__FUNCTION__,
+			$params,
+			'Error: could not login to ' . $nextcloudURL,
+			$response
+		);
+	    }
+	    return array(
+			'success' => false,
+			'error' => 'Error: could not login to ' . $nextcloudURL,
+		);
+	    }
+}
+
+/**
+ * Usage Update
+ * 
+ * Important: Runs daily per server not per product
+ * Run Manually: /admin/reports.php?report=disk_usage_summary&action=updatestats
+ * @param array $params common module parameters
+ * 
+ * @see https://developers.whmcs.com/provisioning-modules/usage-update/
+ */
+function nextcloud_UsageUpdate($params) {
+	$nextcloudURL = $params['serverhttpprefix'] . '://' . $params['serverhostname'] . ':' . $params['serverport'] . "/ocs/v1.php/cloud/users/";
+	$nextcloudTestURL = $params['serverhttpprefix'] . '://' . $params['serverhostname'] . ':' . $params['serverport'] . "/ocs/v1.php/cloud/capabilities";
+	$response = nextcloud_send($nextcloudTestURL, $params['serverusername'],$params['serverpassword'],"GET");
+
+	if ($response === false) {
+	    return "Cannot communicate with server: " . $nextcloudURL;
+	}
+
+	if ($response->ocs->meta->status !== 'ok') {
+		if (isset($response->ocs->meta->message)) {
+		    logModuleCall(
+			'nextcloud',
+			__FUNCTION__,
+			$params,
+			'Error: could not login to ' . $nextcloudURL,
+			$response
+		    );
+		}
+		return 'Error: could not login to ' . $nextcloudURL;
+	}
+
+	$servicesObj = Capsule::table('tblhosting')
+    	    ->select('*')
+    	    ->where('server', '=', $params['serverid'])
+    	    ->where('domainstatus', '=', 'Active')
+    	    ->get();
+	foreach((array)$servicesObj as $serviceObj) {
+		$service = get_object_vars($serviceObj[0]);
+		$response = nextcloud_send($nextcloudURL . "/" . $service['username'], $params['serverusername'],$params['serverpassword'],"GET");
+		
+		$freeMegaBytes =  round($response->ocs->data->quota->free  / 1048576,2);
+		$usedMegaBytes =  round($response->ocs->data->quota->used  / 1048576,2);
+		$quotaMegaBytes = round($response->ocs->data->quota->quota / 1048576,2);
+		
+		if ($response->ocs->meta->status == 'ok') {
+			try {
+				Capsule::table('tblhosting')
+					->where('id', '=', $service['id'])
+					->update(
+						array(
+							'diskusage' => $usedMegaBytes,
+							'disklimit' => $quotaMegaBytes,
+							'lastupdate' => Capsule::raw('now()')
+						)
+					);
+			} catch (Exception $e) {
+				logModuleCall(
+					'nextcloud',
+					__FUNCTION__,
+					$params,
+					'Error: could update usage information for ' . $service['username'],
+					$response->ocs->meta->message
+				);
+			}
+		} else {
+		    logModuleCall(
+			'nextcloud',
+			__FUNCTION__,
+			$params,
+			'Error: could update usage information for ' . $service['username'],
+			$response->ocs->meta->message
+		    );
+		
+		}
+    }
+}
+
+/**
+ * Client area output logic handling.
+ *
+ * This function is used to define module specific client area output. It should
+ * return an array consisting of a template file and optional additional
+ * template variables to make available to that template.
+ *
+ * The template file you return can be one of two types:
+ *
+ * * tabOverviewModuleOutputTemplate - The output of the template provided here
+ *   will be displayed as part of the default product/service client area
+ *   product overview page.
+ *
+ * * tabOverviewReplacementTemplate - Alternatively using this option allows you
+ *   to entirely take control of the product/service overview page within the
+ *   client area.
+ *
+ * Whichever option you choose, extra template variables are defined in the same
+ * way. This demonstrates the use of the full replacement.
+ *
+ * Please Note: Using tabOverviewReplacementTemplate means you should display
+ * the standard information such as pricing and billing details in your custom
+ * template or they will not be visible to the end user.
+ *
+ * @param array $params common module parameters
+ *
+ * @see https://developers.whmcs.com/provisioning-modules/module-parameters/
+ *
+ * @return array
+ */
+function nextcloud_ClientArea($params) {
+	switch ($params['serverport']) {
+		case '80':
+		case '443':
+			$nextcloudURL = $params['serverhttpprefix'] . '://' . $params['serverhostname'];
+			break;
+		default:
+			$nextcloudURL = $params['serverhttpprefix'] . '://' . $params['serverhostname'] . ':' . $params['serverport'];
+			break;
+	};
+	$clientInfo['basequota'] 	= $params['configoption1'] ? $params['configoption1'] : 1;
+	$clientInfo['addonquota'] 	= $params['configoptions']['addonQuota'] ? $params['configoptions']['addonQuota'] : 0;
+	$clientInfo['userquota'] 	= $clientInfo['basequota'] + $clientInfo['addonquota'];
+	$clientInfo['mailaddress'] 	= $params['username'];
+	$clientInfo['webmailurl'] 	= $nextcloudURL;
+	$clientInfo['zimbraserver'] 	= parse_url($clientInfo['webmailurl'], PHP_URL_HOST);
+	$clientinfo['url'] 		= $nextcloudURL;
+	$clientinfo['user']		= $user;
+	$clientinfo['mobile1']		= $app;
+	$clientinfo['mobile2']		= $google;
+	$clientinfo['winclient']	= $winClient;
+	$clientinfo['macclient']	= $macClient;
+	$clientinfo['linClient'] 	= $linClient;
+	$clientinfo['stitle'] 		= $params['model']['product']['name'];
+
+	
+	return array(
+	    'tabOverviewReplacementTemplate' => 'clientarea',
+	    'vars' => $clientInfo,
+	);
+}
+
+
+
+/**
+ * Change the password for a SeaFile account.
+ *
+ * Called when a password change is requested. This can occur either due to a
+ * client requesting it via the client area or an admin requesting it from the
+ * admin side.
+ *
+ * This option is only available to client end users when the product is in an
+ * active status.
+ *
+ * @param array $params common module parameters
+ *
+ * @see https://developers.whmcs.com/provisioning-modules/module-parameters/
+ *
+ * @return string 'success' or an error message
+ */
+function nextcloud_ChangePassword($params) { 
+	$checkPassword = nextcloudCheckPassword($params['password']);
+	if ($checkPassword != null) {
+	    return $checkPassword;
+	}
+	
+	$nextcloudURL = $params['serverhttpprefix'] . '://' . $params['serverhostname'] . ':' . $params['serverport'] . "/ocs/v1.php/cloud/users/" . $params['username'];
+	$post = array('key' => 'password', 'value' => $params["password"]);
+	$response = nextcloud_send($nextcloudURL, $params["serverusername"], $params["serverpassword"], "PUT", $post);
+	
+        if ($response === false) {
+            return "Der Server kann nicht erreicht werden";
+        }
+	if ($response->ocs->meta->status == 'ok') {
+	    return 'success';
+	} else {
+	    if ($response->ocs->meta->statuscode == '107') {
+		return 'Das Passwort entspricht nicht den Grundanforderungen von Nextcloud';
+	    } else {
+		return 'Das Passwort konnte nicht geändert werden. Der Fehlercode war: ' . $response->ocs->meta->statuscode;
+	    }
+	}
+}
+
+/**
+ * Set a new quota of a SeaFile account.
+ *
+ * Called to apply a quota change of the service. It
+ * is called to provision upgrade or downgrade orders, as well as being
+ * able to be invoked manually by an admin user.
+ *
+ * This same function is called for upgrades and downgrades of both
+ * products and configurable options.
+ *
+ * @param array $params common module parameters
+ *
+ * @see https://developers.whmcs.com/provisioning-modules/module-parameters/
+ *
+ * @return string 'success' or an error message
+ */
+function nextcloud_ChangePackage($params) { 
+	$addonQuota    = $params['configoptions']['addonQuota'];
+	$quota         = $params['configoption1'] ? $params['configoption1'] : 1;
+	$accountQuota = ($quota + $addonQuota);
+
+	$nextcloudURL = $params['serverhttpprefix'] . '://' . $params['serverhostname'] . ':' . $params['serverport'] . "/ocs/v1.php/cloud/users/" . $params['username'];
+	$post = array('key' => 'quota', 'value' => $accountQuota . "MB");
+	$response = nextcloud_send($nextcloudURL, $params["serverusername"], $params["serverpassword"], "PUT", $post);
+	
+	if ($response === false) {
+            return "Der Server kann nicht erreicht werden";
+        }
+        
+	if ($response->ocs->meta->status == 'ok') {
+	    try {
+    		Capsule::table('tblhosting')
+        	    ->where('id', '=', $params['serviceid'])
+        	    ->update(
+            	    array(
+                	'disklimit' => $userAccount['quota_total'],
+            	    )
+        	);
+	    } catch (Exception $e) {
+    		logModuleCall(
+        	    'nextcloud',
+        	    __FUNCTION__,
+        	    $params,
+        	    'Error: could not update quota in database',
+        	    $e->getMessage()
+    		);
+		return 'Error: could not update quota in database';
+	    }
+	    if(nextcloudUpdateQuota($params) != 'success') {
+	        return 'Error: could not update addonQuota in database';
+	    };
+	    return 'success';
+	} else {
+	    return 'Der Account konnte nicht modifiziert werden. Der Fehlercode war: ' . $response->ocs->meta->statuscode;
+	}
+}
+
+/**
+ * Provision a new instance of a NextCloud account.
+ *
+ * Attempt to provision a new NextCloud account. This is
+ * called any time provisioning is requested inside of WHMCS. Depending upon the
+ * configuration, this can be any of:
+ * * When a new order is placed
+ * * When an invoice for a new order is paid
+ * * Upon manual request by an admin user
+ *
+ * @param array $params common module parameters
+ *
+ * @see https://developers.whmcs.com/provisioning-modules/module-parameters/
+ *
+ * @return string 'success' or an error message
+ */
+function nextcloud_CreateAccount($params) {
+	$userName      = $params['customfields']['username'];
+	$firstName     = $params['customfields']['firstname'];
+	$lastName      = $params['customfields']['lastname'];
+	$loginEMail    = $params['customfields']['email'];
+        $loginPassword = $params['customfields']['password'];
+	$addonQuota    = $params['configoptions']['addonQuota'];
+	
+	$baseQuota = $params['configoption1'] ? $params['configoption1'] : 1;
+	$addonQuota = $params['configoptions']['addonQuota'] ? $params['configoptions']['addonQuota'] : 0;
+	$newAddQuota = $params['configoptions']['newAddQuota'] ? $params['configoptions']['newAddQuota'] : 0;
+	
+	$accountQuota = $baseQuota + $addonQuota + $newAddQuota;
+	
+	$nextcloudURL = $params['serverhttpprefix'] . '://' . $params['serverhostname'] . ':' . $params['serverport'] . "/ocs/v1.php/cloud/users";
+	$post = array(
+		'userid' 	=> $userName, 
+		'password'	=> $loginPassword,
+		'email' 	=> $loginEMail,
+		'displayName' 	=> $firstName . " " . $lastName,
+		'quota' 	=> $accountQuota . "GB"
+	);
+	$response = nextcloud_send($nextcloudURL, $params["serverusername"], $params["serverpassword"], "POST", $post);
+
+	if ($response === false) {
+	    return "Der Server kann nicht erreicht werden";
+	}
+	
+	if ($response->ocs->meta->status == 'ok' && $response->ocs->meta->statuscode == '100') {
+	    try {
+    		Capsule::table('tblhosting')
+        	    ->where('id', '=', $params['serviceid'])
+        	    ->update(
+            	    array(
+                	'username'  => $userName,
+                	'password'  => $loginPassword,
+                	'disklimit' => $accountQuota * 1024,
+                	'diskusage' => 0,
+            	    )
+        	);
+	    } catch (\Exception $e) {
+    		logModuleCall(
+        	    'nextcloud',
+        	    __FUNCTION__,
+        	    $params,
+        	    'Error: could save username & password in database',
+        	    $e->getMessage()
+    		);
+    		return 'Error: could save username & password in database';
+	    }
+            if(nextcloudUpdateQuota($params) != 'success') {
+                return 'Error: could not update addonQuota in database';
+            };
+	    return 'success';
+	} else {
+	    logModuleCall(
+	    	'nextcloud',
+		__FUNCTION__,
+		$params,
+		'Error: could not create user ' . $userName,
+		$response
+	    );
+	    if ($response->ocs->meta->statuscode == '102') {
+		return "Der Account konnte nicht erstellt werden. Es existiert bereits ein Account mit diesem Namen";
+	    } elseif ($response->ocs->meta->statuscode == '107') {
+		return "Beim Erstellen des Accounts ist ein Fehler aufgetreten, der Fehler war: " . $response->ocs->meta->message;
+	    }
+	}
+}
+
+/**
+ * Set a nextcloud account to status inactive.
+ *
+ * Called when a suspension is requested. This is invoked automatically by WHMCS
+ * when a product becomes overdue on payment or can be called manually by admin
+ * user.
+ *
+ * @param array $params common module parameters
+ *
+ * @see https://developers.whmcs.com/provisioning-modules/module-parameters/
+ *
+ * @return string 'success' or an error message
+ */
+function nextcloud_SuspendAccount($params) {
+	$nextcloudURL = $params['serverhttpprefix'] . '://' . $params['serverhostname'] . ':' . $params['serverport'] . "/ocs/v1.php/cloud/users/" . $params['username'] . "/disable";
+
+	$response = nextcloud_send($nextcloudURL, $params["serverusername"], $params["serverpassword"], "PUT", array() );
+	if ($response === false) {
+            return "Der Server kann nicht erreicht werden";
+        }
+        
+	if ($response->ocs->meta->status == 'ok' && $response->ocs->meta->statuscode == '100') {
+	    return 'success';
+	} else {
+	    logModuleCall(
+		'nextcloud',
+		__FUNCTION__,
+		$params,
+		'Error: could not suspend account ' . $params['username'],
+		$response
+	    );
+	    return 'Der Account konnte nicht deaktiviert werden: ' . $params['username'];
+	}
+}
+
+/**
+ * Set a SeaFile account to status active.
+ *
+ * Called when an un-suspension is requested. This is invoked
+ * automatically upon payment of an overdue invoice for a product, or
+ * can be called manually by admin user.
+ *
+ * @param array $params common module parameters
+ *
+ * @see https://developers.whmcs.com/provisioning-modules/module-parameters/
+ *
+ * @return string 'success' or an error message
+ */
+function nextcloud_UnsuspendAccount($params) {
+	$nextcloudURL = $params['serverhttpprefix'] . '://' . $params['serverhostname'] . ':' . $params['serverport'] . "/ocs/v1.php/cloud/users/" . $params['username'] . "/enable";
+	$response = nextcloud_send($nextcloudURL, $params["serverusername"], $params["serverpassword"], "PUT", array() );
+
+	if ($response === false) {
+            return "Der Server kann nicht erreicht werden";
+        }
+        
+	if ($response->ocs->meta->status == 'ok' && $response->ocs->meta->statuscode == '100') {
+	    return 'success';
+	} else {
+	    logModuleCall(
+		'nextcloud',
+		__FUNCTION__,
+		$params,
+		'Error: could not unsuspend account ' . $params['username'],
+		$response
+	    );
+	    return 'Der Account konnte nicht reaktiviert werden: ' . $params['username'];
+	}
+}
+
+
+/**
+ * Removes a Nextcloud account.
+ *
+ * Called when a termination is requested. This can be invoked automatically for
+ * overdue products if enabled, or requested manually by an admin user.
+ *
+ * @param array $params common module parameters
+ *
+ * @see https://developers.whmcs.com/provisioning-modules/module-parameters/
+ *
+ * @return string 'success' or an error message
+ */
+function nextcloud_TerminateAccount($params) {
+	$nextcloudURL = $params['serverhttpprefix'] . '://' . $params['serverhostname'] . ':' . $params['serverport'] . "/ocs/v1.php/cloud/users/" . $params['username'];
+	$response = nextcloud_send($nextcloudURL, $params["serverusername"], $params["serverpassword"], "DELETE", array() );
+
+	if ($response === false) {
+            return "Der Server kann nicht erreicht werden";
+        }
+
+	if ($response->ocs->meta->status == 'ok' && $response->ocs->meta->statuscode == '100') {
+	    return 'success';
+	} else {
+	    logModuleCall(
+		'nextcloud',
+		__FUNCTION__,
+		$params,
+		'Error: could not delete account ' . $params['username'],
+		$response
+	    );
+	    return 'Der Account konnte nicht gelöscht werden: ' . $params['username'];
+	}
+}
+
+
+
+
+function nextcloud_send($href, $username, $password, $action, $post = array()) {
+    $postdata = http_build_query($post);
+    $ch = curl_init();
+    if (strtoupper($action) == 'POST') {
+        curl_setopt($ch, CURLOPT_POST, true);
+        if ($postdata) {
+            curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
+	}
+    }
+
+    if (strtoupper($action) == 'PUT') {
+        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
+        if ($postdata) {
+            curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
+	}
+    }
+
+    if (strtoupper($action) == 'GET') {
+        curl_setopt($ch, CURLOPT_HTTPGET, true);
+    }
+
+    if (strtoupper($action) == 'DELETE') {
+        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
+    }
+
+    curl_setopt($ch, CURLOPT_URL, $href);
+    curl_setopt($ch, CURLOPT_USERPWD, $username . ":" . $password);
+    curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/json","OCS-APIRequest: true",'content-type: application/x-www-form-urlencoded'));
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
+    $result_json = curl_exec($ch);
+    $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+    curl_close($ch);
+    
+    if ($httpcode >= 200 && $httpcode < 300) {
+        $result_bom = nextcloud_remove_utf8bom($result_json);
+        $result = json_decode($result_bom);
+        return($result);
+    } else {
+	error_log("NextCloud Module nextcloud_send(): Error while executing " . $href . " the result code was: " . $httpcode);
+        logModuleCall(
+	    'nextcloud',
+	    __FUNCTION__,
+	    $result_json,
+	    'nextcloud_send: Error: error in response',
+	    $response
+	);
+        return false;
+    }
+}
+
+function nextcloud_remove_utf8bom($text) {
+    $bom = pack('H*', 'EFBBBF');
+    $text = preg_replace("/^$bom/", '', $text);
+    return $text;
+}
+
+/**
+ * server side password check
+ * 
+ * recheck the client side password check
+ * in case that the client side check has been disabled
+ * 
+ * @param string $pwd password
+ * 
+ * @return string missing features or null if the password matches our needs
+ */
+function nextcloudCheckPassword($pwd) {
+    if (strlen($pwd) < 8) {
+        return 'Das das Passwort ist zu kurz. Es werden mind. 8 Zeichen benötigt';
+    }
+
+    if (!preg_match('#[0-9]+#', $pwd)) {
+        return 'Das Passwort muss mindestens eine Zahl enthalten';
+    }
+
+    if (!preg_match('#[A-Z]+#', $pwd)) {
+        return 'Das Passwort muss mindestens einen Grossbuchstaben (A-Z) enthalten';
+    }     
+
+    if (!preg_match('#[a-z]+#', $pwd)) {
+        return 'Das Passwort muss mindestens einen Kleinbuchstaben (a-z) enthalten';
+    }     
+
+    if (!preg_match('#[^\w]+#', $pwd)) {
+        return 'Das Passwort muss mindestens ein Sonderzeichen (.,-:=) enthalten';
+    }
+    return null;
+}
+
+/**
+ * Perform an update of customfields to prevent downgrades.
+ *
+ * Called in changePackage or createAccount functions.
+ *
+ * @param array $params common module parameters
+ *
+ * @return *success* or an error
+ */
+function nextcloudUpdateQuota($params) {
+    if(isset($params['configoptions']['addonQuota'])) {
+        $addonQuota = $params['configoptions']['addonQuota'] ? $params['configoptions']['addonQuota'] : 0 ;
+        $newAddQuota = $params['configoptions']['newAddQuota'] ? $params['configoptions']['newAddQuota'] : 0;
+        $addonQuota = $addonQuota + $newAddQuota;
+        $addonQuotaFieldIDObj = Capsule::table('tblproductconfigoptions')
+            ->join('tblhostingconfigoptions', 'tblproductconfigoptions.id', '=', 'tblhostingconfigoptions.configid')
+            ->where('tblhostingconfigoptions.relid', '=', $params['serviceid'])
+            ->where('tblproductconfigoptions.optionname', 'like', 'addonQuota%')
+            ->select('tblhostingconfigoptions.id', 'tblproductconfigoptions.qtymaximum')
+            ->get();
+        if($addonQuota > $addonQuotaFieldIDObj[0]->qtymaximum) {
+            logModuleCall(
+                'seafile',
+                __FUNCTION__,
+                $params,
+                'Info: someone is trying to exceed the maximum size',
+                ''
+            );
+            $addonQuota = $addonQuotaFieldIDObj[0]->qtymaximum;
+        }
+        try {
+            $updateAddonQuota = Capsule::table('tblhostingconfigoptions')
+                ->where('id', $addonQuotaFieldIDObj[0]->id)
+                ->update(
+                    [
+                        'qty' => $addonQuota,
+                    ]
+                );
+        } catch (\Exception $e) {
+            logModuleCall(
+                'nextcloud',
+                __FUNCTION__,
+                $updateAddonQuota,
+                'Error: could not save addonOuota in database.',
+                $e->getMessage()
+            );
+            return 'Error: could not save addonOuota in database.';
+        }
+        $newAddQuotaFieldIDObj = Capsule::table('tblproductconfigoptions')
+            ->join('tblhostingconfigoptions', 'tblproductconfigoptions.id', '=', 'tblhostingconfigoptions.configid')
+            ->where('tblhostingconfigoptions.relid', '=', $params['serviceid'])
+            ->where('tblproductconfigoptions.optionname', 'like', 'newAddQuota%')
+            ->select('tblhostingconfigoptions.id')
+            ->get();
+        try {
+            $updateNewAddQuota = Capsule::table('tblhostingconfigoptions')
+                ->where('id', $newAddQuotaFieldIDObj[0]->id)
+                ->update(
+                    [
+                        'qty' => '0',
+                    ]
+                );
+        } catch (\Exception $e) {
+            logModuleCall(
+                'nextcloud',
+                __FUNCTION__,
+                $updateNewAddQuota,
+                'Error: could not reset newAddOuota in database.',
+                $e->getMessage()
+            );
+            return 'Error: could not reset newAddOuota in database.';
+        }
+    }
+    return 'success';
+}
+
+
+
+
+
+?>
+
+
+

+ 1470 - 0
nextcloud.php.old

@@ -0,0 +1,1470 @@
+<?php
+use Illuminate\Database\Capsule\Manager as Capsule;
+if (!defined("WHMCS")) {
+    die("This file cannot be accessed directly");
+}
+function nextcloud_ConfigOptions() {
+
+    global $whmcs;
+    $productid = (int) $_REQUEST['id'];   
+        
+    foreach(Capsule::table('tbladdonmodules')->where('module', 'nextcloud')->whereIn('setting', array('licensekey','nextcloudLicenseStatus'))->get() as $dataLicenseKey){        
+       $stValue = $dataLicenseKey->setting;
+       $$stValue = $dataLicenseKey->value;
+    }    
+    $updatedUserCount = Capsule::table('tblproducts')->where('id', $productid)->update(['configoption1' => $licensekey,]);    
+    $configValues = Capsule::table('tblproducts')->where('id', $productid)->get();
+    $configValues =  (array) $configValues[0];    
+    
+    /*
+     * Fetch nextcloud Groups* Starts
+     */
+    $nextcloudLicenseStatus = 'Active';
+
+    $servername = $configValues['configoption7'];
+
+        
+    $serverDetailsQuery = Capsule::table('tblservers')->where('name', $servername)->where('type', 'nextcloud')->get();
+    $serverDetails =  (array) $serverDetailsQuery[0];
+
+    $apiurl = $configValues['configoption3'];
+    //$apiurl = str_replace('/', DIRECTORY_SEPARATOR, $apiurl);
+
+    if ($serverDetails['secure'] == 'on') {
+            $serverSecure = 'https://';
+    } else {
+        $serverSecure = 'http://';
+        $decryptedpassword = html_entity_decode(decrypt($serverDetails['password']));
+        $href = nextcloud_API_URL($serverSecure, $serverDetails["hostname"], $apiurl, $configValues["configoption5"]);
+        $response = nextcloud_Send($href, $serverDetails["username"], $decryptedpassword, 'get');
+    }
+
+    $groups = array();
+
+    if ($response->ocs->meta->status == 'ok') {
+        foreach ($response->ocs->data->groups as $key => $value):
+            $groups[] = $value;
+        endforeach;
+        unset($groups[array_search("admin", $groups)]);
+    }
+        /*
+         * 
+         * Fetch nextcloud Groups* Ends
+         * 
+         */
+        $create_configurationoptions = empty($configValues['configoption12']) ? false : true;
+        //nextcloud_addCustomfieldsConfigurableFields($productid, $create_configurationoptions, $configValues['configoption14'], $configValues['configoption15'], $configValues['configoption17'], $groups);
+        nextcloud_addCustomfieldsConfigurableFields($productid, true, "GB", false, $configValues['configoption17'], $groups);
+
+        $optionsresult = nextcloud_customfieldsConfigurableOptions($productid);
+        if ($optionsresult['result'] == 'success') {
+            if ($optionsresult['availoptions'] == 0)
+                $options = '-- No options --';
+            else
+                $options = $optionsresult['options'];
+        }
+
+        $quotaunitdescription = "";
+        if (!is_numeric($configValues['configoption10']) && !empty($configValues['configoption10'])) {                
+            Capsule::table('tblproducts')->where('id', $productid)->update(['configoption10' => '']);    
+            $redirect = true;
+        }
+        $quotaType = "text";
+        $quotaFriendlyName = "Quota in GB ";
+        $quotaOptions = "";
+        $quotaDescription = "Please enter value for Quota in Gigabytes";
+
+        $configarray = array(
+    	    /*
+            "nextcloudApiURL" => array(# nextcloud Api Fields 1
+                "FriendlyName" => "API URL",
+                "Type" => "text",
+                "Size" => "35",
+                "Description" => "<a style='text-decoration:none;' href='javacsript::' title='nextcloud API URL(For developer only)'><img src='../modules/addons/nextcloud/images/info.gif'></a>",
+                "Default" => "/ocs/v2.php/cloud/",
+            ),
+            */
+            /*
+            "fetchGroups" => array(# nextcloud Api Fields 2
+                "FriendlyName" => "Group API",
+                "Type" => "text",
+                "Size" => "35",
+                "Description" => "<a style='text-decoration:none;' href='javacsript::' title='nextcloud API to synchronize nextcloud groups(For developer only)'><img src='../modules/addons/nextcloud/images/info.gif'></a>",
+                "Default" => "/groups",
+            ),
+            */
+            "serverName" => array(# nextcloud Api Fields 3
+                "FriendlyName" => "Server Name",
+                "Type" => "text",
+                "Size" => "35",
+                "Description" => "<a style='text-decoration:none;' href='javacsript::' title='Server name which you have configured for nextcloud module'><img src='../modules/addons/nextcloud/images/info.gif'></a>",
+            #"Default" => "Example",
+            ),
+            "autonextcloudLogin" => array(# nextcloud Api Fields 4
+                "FriendlyName" => "Login Button",
+                "Type" => "text",
+                "Size" => "35",
+                "Description" => "<a style='text-decoration:none;' href='javacsript::' title='Text value to show on Auto login nextcloud button in clientarea'><img src='../modules/addons/nextcloud/images/info.gif'></a>",
+            #"Default" => "Example",
+            ),
+
+            "nextcloudUsername" => array(# Clientarea Fields 1
+                "FriendlyName" => "Username",
+                "Type" => "dropdown",
+                "Size" => "35",
+                "Options" => $options,
+                "Description" => "<a style='text-decoration:none;' href='javacsript::' title='Customfield for nextcloud account username'><img src='../modules/addons/nextcloud/images/info.gif'></a>",
+            #"Default" => "Example",
+            ),
+            "nextcloudQuota" => array(# Clientarea Fields 4
+                "FriendlyName" => $quotaFriendlyName,
+                "Type" => $quotaType,
+                "Size" => "28",
+                "Options" => $quotaOptions,
+                "Description" => "<a style='text-decoration:none;' href='javacsript::' title='$quotaDescription'><img src='../modules/addons/nextcloud/images/info.gif'></a>",
+            //"Default" => $quotaDefault,
+            ),
+
+            "nextcloudPassword" => array(# Clientarea Fields 2
+                "FriendlyName" => "Password",
+                "Type" => "dropdown",
+                "Size" => "35",
+                "Options" => $options,
+                "Description" => "<a style='text-decoration:none;' href='javacsript::' title='Customfield for nextcloud account password'><img src='../modules/addons/nextcloud/images/info.gif'></a>",
+            #"Default" => "Example",
+            ),
+            /*
+            "nextcloudGroup" => array(# Clientarea Fields 3
+                "FriendlyName" => $groupFriendlyName,
+                "Type" => $groupType,
+                "Size" => "35",
+                "Options" => $groupOptions,
+                "Description" => "<a style='text-decoration:none;' href='javacsript::' title='" . $groupDescription . "'><img src='../modules/addons/nextcloud/images/info.gif'></a>",
+            #"Default" => "Example",
+            ),
+            */
+            /*
+            "cloudEncoding" => array(# nextcloud Character Settings Field
+                "FriendlyName" => "Encoding",
+                "Type" => "yesno",
+                "Size" => "35",
+                "Description" => "Character Encoding",
+        	"Default" => "Example",
+            ),
+            "quotaManageAdmin" => array(# nextcloud Quota Settings Field
+                "FriendlyName" => "Manage Quota",
+                "Type" => "yesno",
+                "Size" => "35",
+                "Description" => "Allow admin to manage Quota <span></span>",
+            #"Default" => "Example",
+            ),
+            
+            "groupManageAdmin" => array(# nextcloud Quota Settings Field
+                "FriendlyName" => "Manage Group",
+                "Type" => "yesno",
+                "Size" => "35",
+                "Description" => "Allow admin to manage user group <span></span>",
+            #"Default" => "Example",
+            ),
+            "quotaunits" => array(
+                "FriendlyName" => "Quota Units",
+                "Type" => "dropdown",
+                "Options" => "B,KB,MB,GB,TB",
+                "Description" => $quotaunitdescription,
+                "Default" => "GB"
+            ),
+            "userwithoutgroup" => array(
+                "FriendlyName" => "User Group",
+                "Type" => "yesno",
+                "Description" => "Tick if accounts should be created without nextcloud Group <span></span>"
+            ),
+            "enablegrouplimit" => array(
+                "FriendlyName" => "Group Limit",
+                "Type" => "yesno",
+                "Description" => "Tick to Enable Group Limit <span></span> " . $groupLimitHTML . "<tr><td colspan=4 style='font-weight:bold;text-align:center;font-size:13px;'><p class='bg-info' style='padding: 5px;margin: 0px!important;'>Reseller Module Settings</p></td></tr>"
+            ),
+            "customgroup" => array(
+                "FriendlyName" => "Custom Group Name",
+                "Type" => "yesno",
+                "Description" => "Tick if you want users can choose group name at their own <span></span>"
+            ),
+            "groupadmin" => array(
+                "FriendlyName" => "Group Admin",
+                "Type" => "yesno",
+                "Description" => "Tick if you want to make user admin of own created groups <span></span>",
+            ),
+            "defaultlimitnewlycreatedgroup" => array(
+                "FriendlyName" => "Default Account Limit",
+                "Type" => "text",
+                "Description" => "Only fill, if  <b>Custom Group Name</b> option is ticked"
+            ),
+            */
+            "emailtemplate" => array(
+                "FriendlyName" => "Email Template Name",
+                "Type" => "text",
+                "Size" => "35",
+                "Description" => "Do not leave it empty to resend email",
+                "Default" => "nextcloud Account Welcome Email"
+            ),
+            /*
+	    "nextcloudApiAppURL" => array(# nextcloud Api Fields 1
+                "FriendlyName" => "API APP URL",
+                "Type" => "text",
+                "Size" => "35",
+                "Description" => "<a style='text-decoration:none;' href='javacsript::' title='nextcloud API URL(For developer only)'><img src='../modules/addons/nextcloud/images/info.gif'></a>",
+                "Default" => "/ocs/v2.php/apps/",
+            ),
+            */
+        );
+        
+    if (Capsule::table('tblemailtemplates')->where('name','nextcloud Account Welcome Email')->count() <= 0) {
+        Capsule::connection()->transaction(
+            function ($connectionManager)  {                    
+                $connectionManager->table('tblemailtemplates')->insert(
+                    [
+                        'name' => 'nextcloud Account Welcome Email',
+                        'type' => 'product',
+                        'subject' => 'New nextcloud Account Information',
+                        'message' => '<span>Dear {$client_name},<br /><br />Thank you for your order from us! Your nextcloud account has now been setup and this email contains all the information you will need in order to begin using your account.<br /><br /><strong>New Account Information</strong><br /><br />Domain : {$serverDomain}<br /><br /><strong>Login Details<br /><br /></strong>Username : {$username}<br />Password : {$password}<br /><br /></span><div><span>{$signature}</span></div>',
+                        'custom' => '1',
+                        'plaintext' => '0',
+                    ]
+                );
+            }
+        );
+    }
+    return $configarray;
+}
+
+function nextcloud_CreateAccount($params) {
+    if (nextcloud_checkLicense_server_file() != 'Active') {
+        return "Your license is " . nextcloud_checkLicense_server_file();
+    }
+
+    $encoding = true; // (empty($params['configoption11'])) ? false : true;
+
+    $action = 'post';
+    # Username
+    $USERNAME = substr($params['configoption4'], strpos($params['configoption4'], ':') + 1);
+    $USERNAME = nextcloud_character_encoding($USERNAME, $encoding);
+    $cfData = explode('|',$USERNAME);
+    if(count($cfData)>=2){
+        $USERNAME = $cfData[0];
+    }
+    # Password
+    $PASSWORD = substr($params['configoption6'], strpos($params['configoption6'], ':') + 1);
+    $PASSWORD = nextcloud_character_encoding($PASSWORD, $encoding);
+    $cfData = explode('|',$PASSWORD);
+    if(count($cfData)>=2){
+        $PASSWORD = $cfData[0];
+    }
+
+    # Server Name
+    $servername = $params['configoption7'];
+    $servername = nextcloud_character_encoding($servername, $encoding);
+    # API URL
+    $apiurl = $params['configoption3'];
+	$apiAppurl = $params['configoption21'];
+    //$apiurl = str_replace('/', DIRECTORY_SEPARATOR, $apiurl);
+
+    if ($params['serversecure'] == 'on') {
+        $serverSecure = 'https://';
+    } else {
+        $serverSecure = 'http://';
+    }
+
+    if ($params["serverusername"] == "" || $params["serverpassword"] == "" || $params["serverhostname"] == "") {
+        return "Please check your server configuration or Server is not assinged to the module";
+    }
+
+
+    if (empty($params['configoption10'])) {
+            return 'You did not enter value for Quota';
+    } else {
+            $Quota = trim($params['configoption10']) . " GB";
+    }
+
+    if (!$params['configoption15']) {
+        if ($params['configoption13']) {
+            if (empty($params['configoption8'])) {
+                return 'You have enabled option "Manage Group", But you did not save value for group';
+            } else {
+                $groupname = trim($params['configoption8']);
+            }
+        } else {
+            $GROUPS = substr($params['configoption8'], strpos($params['configoption8'], ':') + 1);
+            $GROUPS = nextcloud_character_encoding($GROUPS, $encoding);
+            $cfData = explode('|',$GROUPS);
+            if(count($cfData)>=2){
+                $GROUPS = $cfData[0];
+            }
+            $groupname = $params["customfields"][$GROUPS];
+        }
+    }
+
+
+    # Get services using same package
+    $countservicesq = Capsule::select("SELECT COUNT(*) as `services` FROM `tblhosting` WHERE `packageid`=" . $params["packageid"] . " AND `domainstatus`='Active'");
+    $countservicesd = (array) $countservicesq;
+    # Get Account Limit from nextcloud
+    $href1 = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiAppurl, $params["configoption2"], "/getgrouplimit/" . $groupname);
+    $response1 = nextcloud_Send($href1, $params["serverusername"], $params["serverpassword"], 'get');
+    $nextcloudGroupLimit = $response1->ocs->data->limit;
+    
+    $nextcloudGroupLimit = empty($nextcloudGroupLimit) ? 0 : $nextcloudGroupLimit;		
+	# if response is not there
+
+
+    
+	#Get Users in Group
+    //$href1 = nextcloud_API_URL($serverSecure, $params["serverhostname"], "/ocs/v2.php/apps/", $params["configoption2"], "/usersingroup/" . $groupname);
+    $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiurl, 'groups/'.$groupname.'/users');
+    $response1 = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], 'get');
+    $usersInGroup = $response1->ocs->data->users;
+    $totalNoOfUsers = count($response1->ocs->data->users);
+    $usersInGroup = empty($usersInGroup) ? array() : $usersInGroup; # if response is not there
+
+	
+    if($params['configoption17']){
+        if($totalNoOfUsers >= $params['configoption19']){
+            return "You have set " . $groupname . ' group account limit is ' . $params['configoption19'] . ' in product module setting. You cannot exceed your group account limit.';
+        }
+    }
+
+	
+    if ($params['configoption16'] && !$params['configoption15']) {
+        $glimitq = Capsule::select("SELECT `accountlimit` FROM `mod_nextcloud_grouplimit` WHERE `productid`=" . $params["packageid"] . " AND `group`='" . $groupname . "'");        
+        $glimitd = (array) $glimitq;
+        if ($glimitd["accountlimit"] > 0 && $countservicesd['services'] >= $glimitd["accountlimit"]) { # 0 is for default nextcloud behaviour
+            return $groupname . ' group account limit is ' . $glimitd["accountlimit"] . ' You cannot exceed your group account limit.';
+        } elseif ($glimitd["accountlimit"] == 0 && $nextcloudGroupLimit != 0 && $nextcloudGroupLimit <= count($usersInGroup)) {
+
+            return $groupname . ' group account limit is ' . $glimitd["accountlimit"] . ' You cannot exceed your group account limit.';
+        }
+    }
+
+
+
+    # If group limit is not defined by whmcs, then it will use nextcloud's group limit if defined otherwise to unlimied accounts 
+    if (!$params["configoption16"] && !$params['configoption15']) {
+        if ($nextcloudGroupLimit != 0 && $nextcloudGroupLimit < count($usersInGroup)) {
+            return $groupname . ' group account limit is ' . $nextcloudGroupLimit . ' You cannot exceed your group account limit.';
+        }
+    }
+    ## Manage user group by admin * Ends
+     $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiurl, 'users');
+    $post = array('userid' => $params["customfields"][$USERNAME], 'password' => $params["customfields"][$PASSWORD]);
+    $response = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], $action, $post);    
+
+    # log module call 1
+    $requeststring = $post;
+    $responsedata = array();
+    $processeddata = (array) $response;
+    $replacevars = array();
+    logModuleCall("nextcloud", "create account => create user", $requeststring, $responsedata, $processeddata, $replacevars);
+
+    if (empty($response)):
+        return 'Please Enable WHMCS Integration APP from your nextcloud installation';
+    endif;
+
+    if ($response->ocs->meta->status == 'failure'): # if nextcloud admin login details are incorrect
+        return 'Please make sure you have entered correct nextcloud admin login details while configuring server or ' . $response->ocs->meta->message;
+    endif;
+
+    if ($response->status == 'failed'):
+        return 'Please make sure module configured successfully';
+    endif;
+
+    if ($response->ocs->meta->status == 'ok'):
+        # Add Email Address to nextcloud Account
+        $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiurl, 'users/' . $params["customfields"][$USERNAME]);
+        $post = array('key' => 'email', 'value' => $params['clientsdetails']['email']);
+        nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], "put", $post);
+        #######################################
+        # User without Group
+        if ($params['configoption15']) { # Condition to create user without group
+            $responseg->ocs->meta->status = 'ok';
+        } else {
+            
+            
+            
+            
+//            $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiurl, 'users/' . $params["customfields"][$USERNAME] . '/groups');
+//            $post = array('groupid' => $groupname);
+//            $responseg = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], "post", $post);
+//            
+            
+            $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiAppurl , "whmcsintegration/togglegroups?format=json");
+            $post = array("userid" => $params["customfields"][$USERNAME], "groups" => json_encode(array($groupname)));
+            $responseg = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], "post", $post);            
+            # log module call 2
+            $requeststring = $post;
+            $responsedata = array();
+            $processeddata = (array) $responseg;
+            $replacevars = array();
+            logModuleCall("nextcloud", "create account => assign group", $requeststring, $responsedata, $processeddata, $replacevars);
+        }
+
+        if (!empty($groupname) || $params['configoption15']): # Condition afer user added to group success
+        //if ($responseg->ocs->meta->status == 'ok'): # Condition afer user added to group success
+            # Make user group admin
+            if ($params['configoption18']) {
+                $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiurl, 'users/' . $params["customfields"][$USERNAME] . '/subadmins');
+                $post = array('groupid' => $groupname);
+                nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], "post", $post);
+            }
+            # #####################
+            $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiurl, 'users/' . $params["customfields"][$USERNAME]);
+            $post = array('key' => 'quota', 'value' => $Quota);
+            $responseq = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], "put", $post);
+            if ($responseq->ocs->meta->status == 'ok'):
+                /*
+                 * 
+                 * Clear service username and password
+                 * 
+                 */                
+                Capsule::update("update tblhosting set username = '', password='' where id='".$params["serviceid"]."'");
+                /*
+                 * Send nextcloud account welcome email to user
+                 */
+
+                $command = "sendemail";
+                $adminuser = nextcloud_getAdminId();
+                $values["messagename"] = trim($params['configoption20']);
+                $values["id"] = $params['serviceid'];
+                $values["customvars"] = base64_encode(serialize(array("domain" => $params["serverhostname"], "username" => $params["customfields"][$USERNAME], "password" => $params["customfields"][$PASSWORD])));
+                localAPI($command, $values, $adminuser);
+                $result = 'success';
+            else:
+                $result = "Error occurred while adding quota for user";
+            endif;
+
+            # log module call 3
+            $requeststring = $post;
+            $responsedata = array();
+            $processeddata = (array) $responseq;
+            $replacevars = array();
+            logModuleCall("nextcloud", "create account => assign quota", $requeststring, $responsedata, $processeddata, $replacevars);
+
+        else:
+            $result = "Error occurred while adding user to group";
+        endif;
+
+    else:
+        $result = "Error occurred while creating a new user";
+    endif;
+
+    return $result;
+}
+
+function nextcloud_TerminateAccount($params) {
+
+    $encoding = (empty($params['configoption11'])) ? false : true;
+    
+    $result = Capsule::table('tblhosting')->select('domainstatus')->where('id',$params['serviceid'])->get();
+    $data = (array) $result[0];
+
+    if ('Terminated' == $data['domainstatus']) {
+        return 'Your current status of service is already Terminated';
+    }
+    $action = 'delete';
+    # Username
+    $USERNAME = substr($params['configoption4'], strpos($params['configoption4'], ':') + 1);
+    $USERNAME = nextcloud_character_encoding($USERNAME, $encoding);
+    $cfData = explode('|',$USERNAME);
+    if(count($cfData)>=2){
+        $USERNAME = $cfData[0];
+    }
+    # API URL
+    $apiurl = $params['configoption3'];
+    //$apiurl = str_replace('/', DIRECTORY_SEPARATOR, $apiurl);
+
+
+    $serverSecure = 'https://';
+    $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiurl, 'users/' . $params["customfields"][$USERNAME]);
+
+    $response = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], $action);
+
+    if ($response->ocs->meta->status == 'ok') {
+        $result = 'success';
+    } else {
+        $result = 'Your service does not terminated successfully';
+    }
+
+    # log module call
+    $requeststring = $post;
+    $responsedata = array();
+    $processeddata = (array) $response;
+    $replacevars = array();
+    logModuleCall("nextcloud", "terminate account", $requeststring, $responsedata, $processeddata, $replacevars);
+
+    return $result;
+}
+
+function nextcloud_SuspendAccount($params) {
+
+    $encoding = (empty($params['configoption11'])) ? false : true;
+
+    $result = Capsule::select("select domainstatus from tblhosting where id='".$params['serviceid']."' ");
+    if ('Suspended' == $result[0]->domainstatus) {
+        return 'Your current status of service is already Suspended';
+    }
+
+    $action = 'post';
+    # Username
+    $USERNAME = substr($params['configoption4'], strpos($params['configoption4'], ':') + 1);
+    $USERNAME = nextcloud_character_encoding($USERNAME, $encoding);
+    $cfData = explode('|',$USERNAME);
+    if(count($cfData)>=2){
+        $USERNAME = $cfData[0];
+    }
+
+    if ($params['serversecure'] == 'on')
+        $serverSecure = 'https://';
+    else
+        $serverSecure = 'http://';
+    # API URL
+    //$apiurl = '/ocs/v2.php/apps/';
+	$apiAppurl = $params['configoption21'];
+    $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiAppurl, $params["configoption2"], '/suspenduser');
+        
+    $post = array("userid" => $params["customfields"][$USERNAME]);    
+    $response = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], $action, $post);
+
+    if ($response->ocs->meta->status == 'ok'):
+        $result = 'success';
+    else:
+        $result = 'Your service does not suspended successfully';
+    endif;
+
+    # log module call
+    $requeststring = $post;
+    $responsedata = array();
+    $processeddata = (array) $response;
+    $replacevars = array();
+    logModuleCall("nextcloud", "suspend account", $requeststring, $responsedata, $processeddata, $replacevars);
+
+    return $result;
+}
+
+function nextcloud_UnsuspendAccount($params) {
+
+    $encoding = (empty($params['configoption11'])) ? false : true;
+
+    $result = Capsule::select("select domainstatus from tblhosting where id='".$params['serviceid']."' ");
+    if ('Suspended' != $result[0]->domainstatus) {
+        return 'Your current status of service is not suspended, Only suspended service can be unsuspended';
+    }
+
+    $action = 'post';
+    # Username
+    $USERNAME = substr($params['configoption4'], strpos($params['configoption4'], ':') + 1);
+    $USERNAME = nextcloud_character_encoding($USERNAME, $encoding);
+    $cfData = explode('|',$USERNAME);
+    if(count($cfData)>=2){
+        $USERNAME = $cfData[0];
+    }
+    if ($params['serversecure'] == 'on')
+        $serverSecure = 'https://';
+    else
+        $serverSecure = 'http://';
+    # API URL
+    //$apiurl = '/ocs/v2.php/apps/';
+	$apiAppurl = $params['configoption21'];
+    $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiAppurl, $params["configoption2"], '/unsuspenduser');
+    $post = array("userid" => $params["customfields"][$USERNAME]);
+    $response = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], $action, $post);
+    if ($response->ocs->meta->status == 'ok'):
+        $result = 'success';
+    else:
+        $result = 'Your module command failed to unsuspended your service';
+    endif;
+
+    # log module call
+    $requeststring = $post;
+    $responsedata = array();
+    $processeddata = (array) $response;
+    $replacevars = array();
+    logModuleCall("nextcloud", "unsuspend account", $requeststring, $responsedata, $processeddata, $replacevars);
+
+    return $result;
+}
+
+function nextcloud_ChangePassword($params) {
+
+    if (nextcloud_checkLicense_server_file() != 'Active') {
+        return "Your license is " . nextcloud_checkLicense_server_file();
+    }
+
+    $encoding = (empty($params['configoption11'])) ? false : true;
+
+    # Username
+    $USERNAME = substr($params['configoption4'], strpos($params['configoption4'], ':') + 1);
+    $USERNAME = nextcloud_character_encoding($USERNAME, $encoding);
+    $cfData = explode('|',$USERNAME);
+    if(count($cfData)>=2){
+        $USERNAME = $cfData[0];
+    }
+    # Password
+    $PASSWORD = substr($params['configoption6'], strpos($params['configoption6'], ':') + 1);
+    $PASSWORD = nextcloud_character_encoding($PASSWORD, $encoding);
+    $PASSWORD02 = $PASSWORD;
+    $cfData = explode('|',$PASSWORD);
+    if(count($cfData)>=2){
+        $PASSWORD = $cfData[0];
+    }
+    # API URL
+    $apiurl = $params['configoption3'];
+    //$apiurl = str_replace('/', DIRECTORY_SEPARATOR, $apiurl);
+
+    if ($params['serversecure'] == 'on')
+        $serverSecure = 'https://';
+    else
+        $serverSecure = 'http://';
+
+    $P = $params["customfields"][$PASSWORD];
+
+    $action = 'put';
+    $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiurl, 'users/' . $params["customfields"][$USERNAME]);
+    $post = array('key' => 'password', 'value' => $params["password"]);    
+    $response = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], $action, $post);
+
+    if ($response->ocs->meta->status == 'ok'):        
+        
+        Capsule::update("UPDATE `tblcustomfieldsvalues` SET value='" . $params["password"] . "' WHERE relid=" . $params["serviceid"] . " && fieldid=(SELECT id FROM `tblcustomfields` WHERE type='product' && relid=" . $params["pid"] . " && fieldname='" . $PASSWORD02 . "' && fieldtype='password')");
+        $result = 'success';
+    else:
+        $result = $response->ocs->meta->message;
+    endif;
+
+    # log module call
+    $requeststring = $post;
+    $responsedata = array();
+    $processeddata = (array) $response;
+    $replacevars = array();
+    logModuleCall("nextcloud", "change password", $requeststring, $responsedata, $processeddata, $replacevars);
+
+    return $result;
+}
+
+function nextcloud_ChangePackage($params) { # Only upgrade/downgrade quota
+    $encoding = (empty($params['configoption11'])) ? false : true;
+    # Username
+    $USERNAME = substr($params['configoption4'], strpos($params['configoption4'], ':') + 1);
+    $USERNAME = nextcloud_character_encoding($USERNAME, $encoding);
+    $cfData = explode('|',$USERNAME);
+    if(count($cfData)>=2){
+        $USERNAME = $cfData[0];
+    }
+
+    # Server Name
+    $servername = $params['configoption7'];
+    $servername = nextcloud_character_encoding($servername, $encoding);
+    # API URL
+    $apiurl = $params['configoption3'];
+	$apiAppurl = $params['configoption21'];
+    //$apiurl = str_replace('/', DIRECTORY_SEPARATOR, $apiurl);
+
+    if ($params['serversecure'] == 'on')
+        $serverSecure = 'https://';
+    else
+        $serverSecure = 'http://';
+
+    if ($params["serverusername"] == "" || $params["serverpassword"] == "" || $params["serverhostname"] == "") {
+        return "Please check your server configuration or Server is not assinged to the module";
+    }
+
+    
+    if ($params['configoption13']) {
+        $groupname = $params['configoption8'];
+        $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiAppurl , "whmcsintegration/togglegroups?format=json");
+        $post = array("userid" => $params["customfields"][$USERNAME], "groups" => json_encode(array($groupname)));
+        $responseg = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], "post", $post);  
+    }    
+    
+    
+    
+    if ($params["configoption12"] == 'on') { # Quota set by admin
+        $Quota = $params["configoption10"] . " " . $params["configoption14"];
+    } else { # Quota set by customer
+        if($params['configoptions']['Quota in GB'] != 0){
+			$QUOTA = substr($params['configoption10'], strpos($params['configoption10'], ':') + 1);
+			$QUOTA = nextcloud_character_encoding($QUOTA, $encoding);
+                        $cfData = explode('|',$QUOTA);
+                        if(count($cfData)>=2){
+                            $QUOTA = $cfData[0];
+                        }
+			$Quota = $params['configoptions'][$QUOTA] . " " . $params['configoption14'];
+		}		
+		else{
+			$query = Capsule::table('tblproductconfiglinks')->select('gid')->where('pid',$params['pid'])->get();
+			$config_group_id = $query[0]->gid;
+			$query2 = Capsule::table('tblproductconfigoptions')->select('id','qtymaximum')->where('gid',$config_group_id)->get();    
+			Capsule::table('tblhostingconfigoptions')->where('relid',$params['serviceid'])->where('configid',$query2[0]->id)->update(['qty' =>$query2[0]->qtymaximum]);;    
+			$Quota = $query2[0]->qtymaximum . " " . $params['configoption14'];
+		}			
+    }
+    $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiurl, 'users/' . $params["customfields"][$USERNAME]);
+	$post = array('key' => 'quota', 'value' => $Quota);	
+	//echo "----------------".$params['configoptions']['Quota in GB'];	
+	//die();
+    $responseq = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], "put", $post);
+    logModuleCall("nextcloud", "change package", $post, (array) $responseq);
+    if ($responseq->ocs->meta->status == 'ok'):
+        return 'success';
+    else:
+        return 'Error occurred while adding quota for user';
+    endif;
+}
+
+function nextcloud_getLang($params) {
+    global $CONFIG;
+    if (!empty($_SESSION['Language']))
+        $language = strtolower($_SESSION['Language']);
+    else if (strtolower($params['clientsdetails']['language']) != '')
+        $language = strtolower($params['clientsdetails']['language']);
+    else
+        $language = $CONFIG['Language'];
+
+    $langfilename = dirname(__FILE__) .'/lang/'. $language . '.php';
+    if (file_exists($langfilename))
+        require_once($langfilename);
+    else
+        require_once(dirname(__FILE__) . '/lang/english.php');    
+    if (isset($lang))
+        return $lang;
+}
+
+
+
+function nextcloud_ClientArea($params) {
+    if (nextcloud_checkLicense_server_file() != 'Active') {
+        return "Your license is " . nextcloud_checkLicense_server_file();
+    }
+    $langVar = nextcloud_getLang($params);        
+    if ($params['serversecure'] == 'on')
+        $serverSecure = 'https://';
+    else
+        $serverSecure = 'http://';
+
+    $encoding = (empty($params['configoption11'])) ? false : true;
+    if(empty($_REQUEST))
+    {
+        $code='';
+        return $code;
+    }
+    # Username
+    $USERNAME = substr($params['configoption4'], strpos($params['configoption4'], ':') + 1);
+    $USERNAME = nextcloud_character_encoding($USERNAME, $encoding);
+    $cfData = explode('|',$USERNAME);
+    if(count($cfData)>=2){
+        $USERNAME = $cfData[0];
+    }
+    # Password
+    $PASSWORD = substr($params['configoption6'], strpos($params['configoption6'], ':') + 1);
+    $PASSWORD = nextcloud_character_encoding($PASSWORD, $encoding);
+    $cfData = explode('|',$PASSWORD);
+    if(count($cfData)>=2){
+        $PASSWORD = $cfData[0];
+    }
+    # API URL
+    $apiurl = $params['configoption3'];
+		$apiAppurl = $params['configoption21'];
+    //$apiurl = str_replace('/', DIRECTORY_SEPARATOR, $apiurl);
+    # Login button value
+    $nextcloudlogin = $params['configoption9'];
+    $nextcloudlogin = nextcloud_character_encoding($nextcloudlogin, $encoding);
+
+        //$autologin = '<form action="' . $serverSecure . $params['serverhostname'] . $apiAppurl.$params["configoption2"].'/autologinuser" method="post" target="_blank" name="login">
+ $autologin = '<form action="' . $serverSecure . $params['serverhostname'].'/index.php/login" method="post" target="_blank" name="login">
+			<input type="hidden" name="username" value="' . $params["customfields"][$USERNAME] . '" />
+            <input type="hidden" name="password" value="' . $params["customfields"][$PASSWORD] . '" />
+            <input type="submit" value="' . $nextcloudlogin . '" class="btn btn-warning modulebutton" />
+            </form>';
+    if (isset($_POST["nextcloud_email"])) {
+        # API URL
+        $appapiurl = $params['configoption21'];
+        if (empty($_POST["nextcloud_email"])) {
+            $action = 'post';
+            $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $appapiurl, $params["configoption2"], '/deluservalue');
+            $post = array('userid' => $params["customfields"][$USERNAME], 'app' => 'settings', 'key' => 'email');
+            $res = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], $action, $post);
+        } else {
+            $action = 'put';
+            $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiurl, 'users/' . $params["customfields"][$USERNAME]);
+            $post = array('key' => 'email', 'value' => trim($_POST["nextcloud_email"]));
+            $res = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], $action, $post);
+        }
+        # log module call
+        $requeststring = $post;
+        $responsedata = array();
+        $processeddata = (array) $res;
+        $replacevars = array();
+        logModuleCall("nextcloud", "Change Email Address", $requeststring, $responsedata, $processeddata, $replacevars);
+    }
+    $action = 'get';
+    $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiurl, 'users/' . $params["customfields"][$USERNAME]);
+    $response = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], $action);
+    $email = $response->ocs->data->email;
+    $code = '<form method="post" action="clientarea.php?action=productdetails&id=' . $params["serviceid"] . '"><div class="panel panel-default">
+    <div class="panel-heading">
+        <h3 class="panel-title">'.$langVar['nextcloudSettings'].'</h3>
+    </div>
+    <div class="panel-body text-center">
+        <div class="row">
+            <div class="col-sm-3 col-xs-6"><div class="form-group">'.$langVar['EmailAddress'].'</div></div>
+            <div class="col-sm-6 col-xs-6">
+                        <div class="form-group"><input type="text" name="nextcloud_email" value="' . $email . '" class="form-control" placeholder="'.$langVar['nextcloudEmailAddress'].'"></div>
+           </div></div>
+    <div class="row">
+    <div class="col-sm-12 col-xs-12">
+    <div class="form-group"><input type="submit" class="btn btn-primary" value="'.$langVar['ChangenextcloudEmailAddress'].'"></div></div>
+    </div>
+    </div></div></form>';
+
+    $code .= '<div class="row"><div class="col-sm-12 col-xs-12">
+    <div class="form-group">' . $autologin . '</div></div></div>';
+
+    return $code;
+}
+
+function nextcloud_AdminLink($params) {
+    $action = 'get';
+    if ($params['serversecure'] == 'on')
+        $serverSecure = 'https://';
+    else
+        $serverSecure = 'http://';
+
+    # API URL
+    $apiurl = $params['configoption3'];
+	$apiAppurl = $params['configoption21'];
+    //$apiurl = str_replace('/', DIRECTORY_SEPARATOR, $apiurl);
+
+    $href = nextcloud_API_URL($serverSecure, $params["serverhostname"], $apiurl, $APP_ID, 'groups');
+    $response = nextcloud_Send($href, $params["serverusername"], $params["serverpassword"], $action);
+
+    if ($response->status == 'failed'):
+        $value = 'Enable nextcloud APP';
+    else:
+        $value = 'Disable nextcloud APP';
+    endif;
+
+    $code = '<form action="' . $serverSecure . $params["serverhostname"] . '" method="post" target="_blank" name="login">
+        <input type="hidden" name="user" value="' . $params["serverusername"] . '" />
+        <input type="hidden" name="password" value="' . $params["serverpassword"] . '" />
+	<input type="submit" value="' . $value . '" />
+	</form>';
+    return $code;
+}
+
+###########################################################################################################################
+################################################## Custom Functions #######################################################
+###########################################################################################################################
+
+function nextcloud_character_encoding($str, $encoding) {
+
+    $string = ($encoding) ? nextcloud_Encoding::fixUTF8($str) : $str;
+
+    return $string;
+}
+
+function nextcloud_getAdminId() {
+    $Query =  Capsule::select("SELECT id FROM `tbladmins` LIMIT 1");
+    $Id = $Query[0]->id;
+    return $Id;
+}
+
+function nextcloud_customfieldsConfigurableOptions($productid) {
+
+    $query = "SELECT concat('CustomField:', fieldname) as ufieldname FROM tblcustomfields WHERE type='product' and relid=" . mysql_real_escape_string($productid) . " UNION SELECT concat('ConfigOption:', optionname) FROM tblproductconfigoptions A, tblproductconfiglinks B WHERE A.gid = B.gid AND B.pid=" . mysql_real_escape_string($productid);    
+    $result = Capsule::select($query);
+    $numberOfOptions = 0;
+    $optionsAr = array();    
+    foreach($result as $key => $optionValue02) {        
+        $optionValue = (array) $optionValue02;
+        $optionsAr[] = $optionValue['ufieldname'];
+        $numberOfOptions++;
+    }    
+    $options = implode(",", $optionsAr);    
+    return array('result' => 'success', 'availoptions' => $numberOfOptions, 'options' => $options);
+}
+
+function nextcloud_addCustomfieldsConfigurableFields($productid, $create_configurationoptions, $quotaunits, $enablegroup, $customgroup, $groups) {
+
+    ######################## CREATE CUSTOMFIELDS ######################
+    $customfieldresult = Capsule::table('tblcustomfields')->where('type','product')->where('relid',$productid)->count();  
+    $customfields = array(
+            "Username" => "text",
+            "Password" => "password"
+    );
+    
+    $addcustomfielddesc = '';
+    $addfieldoptions = '';
+    $addregexpr = '';
+    $addadminonly = '';
+    $addrequired = 'on';
+    $addshoworder = 'on';
+    $addshowinvoice = '';
+    $addsortorder = '';
+    foreach ($customfields as $addfieldname => $addfieldtype) {
+        if ($addfieldtype == "dropdown") {
+            $addfieldoptions = implode(",", $groups);
+	}
+	if ($addfieldtype == "password") {
+            $addcustomfielddesc = "Password must be at least 8 characters, no more than 18 characters.";
+	    $addregexpr = "/^.{8,}$/";
+        } else {
+	    $addcustomfielddesc = "";
+	    $addregexpr = "";
+	}
+	if ($customfieldresult == 0) {   
+            Capsule::table('tblcustomfields')->insert(
+                [
+                    'type' => 'product',
+                    'relid' => $productid,
+                    'fieldname' => $addfieldname,
+                    'fieldtype' => $addfieldtype,
+                    'description' => $addcustomfielddesc,
+                    'fieldoptions' => $addfieldoptions,
+                    'regexpr' => html_entity_decode($addregexpr),
+                    'adminonly' => $addadminonly,
+                    'required' => $addrequired,
+                    'showorder' => $addshoworder,
+                    'showinvoice' => $addshowinvoice,
+                    'sortorder' => $addsortorder,
+                ]                    
+    	    );
+	} else {
+	    $customfieldcount = Capsule::table("tblcustomfields")->where('type','product')->where('relid',$productid)->where("fieldname",$addfieldname)->count();
+	    if($customfieldcount == 0){
+		Capsule::table('tblcustomfields')->insert(
+                    [
+                        'type' => 'product',
+                        'relid' => $productid,
+                        'fieldname' => $addfieldname,
+                        'fieldtype' => $addfieldtype,
+                        'description' => $addcustomfielddesc,
+                        'fieldoptions' => $addfieldoptions,
+                        'regexpr' => html_entity_decode($addregexpr),
+                        'adminonly' => $addadminonly,
+                        'required' => $addrequired,
+                        'showorder' => $addshoworder,
+                        'showinvoice' => $addshowinvoice,
+                        'sortorder' => $addsortorder,
+                    ]                    
+        	);
+	    } else {
+		Capsule::table("tblcustomfields")->where('type','product')->where('relid',$productid)->where("fieldname",$addfieldname)->update(
+		    [
+                        'type' => 'product',
+                        'relid' => $productid,
+                        'fieldname' => $addfieldname,
+                        'fieldtype' => $addfieldtype,
+                        'description' => $addcustomfielddesc,
+                        'fieldoptions' => $addfieldoptions,
+                        'regexpr' => html_entity_decode($addregexpr),
+                        'adminonly' => $addadminonly,
+                        'required' => $addrequired,
+                        'showorder' => $addshoworder,
+                        'showinvoice' => $addshowinvoice,
+                        'sortorder' => $addsortorder,
+                    ] 
+		);
+	    }
+	}
+    }
+	
+    if ($create_configurationoptions) {
+        nextcloud_unlinkproductconfigoptions($productid);
+    } else {
+
+	######################## CONFIGURABLE OPTION #####################
+	$addconfigrablegroupname = "nextcloud Storage" . $productid;
+        $addconfigurabledescription = "Quota in " . $quotaunits;
+	$addconfigurableoptionname = "Quota in " . $quotaunits;
+
+        $configurableoptionresult = Capsule::table('tblproductconfiglinks')->where('pid',$productid)->count();                
+	$configurableoptionresultbynameR = Capsule::table('tblproductconfiggroups')->where('name',$addconfigrablegroupname)->count();
+        $configurableoptionresultbyname = Capsule::select("select id from tblproductconfiggroups where name='".$addconfigrablegroupname."'");
+	$configurableoptionresultbynamedata["id"] = $configurableoptionresultbyname[0]->id;
+        if($configurableoptionresultbynameR > 0 && $configurableoptionresult == 0){
+            Capsule::table('tblproductconfiglinks')->insert(
+                        [
+                            'gid' => $configurableoptionresultbynamedata["id"],
+                            'pid' => $productid,
+                        ]
+                    );                
+        } else if ($configurableoptionresult == 0) {
+    
+            $configurablegroupid = Capsule::table('tblproductconfiggroups')->insertGetId(
+                        [
+                            'name' => $addconfigrablegroupname,
+                            'description' => $addconfigurabledescription,
+                        ]
+                    );
+            
+            Capsule::table('tblproductconfiglinks')->insertGetId(
+                        [
+                            'gid' => $configurablegroupid,
+                            'pid' => $productid,
+                        ]
+                    );
+            
+            $configid = Capsule::table('tblproductconfigoptions')->insertGetId(
+                        [
+                            'gid' => $configurablegroupid,
+                            'optionname' => $addconfigurableoptionname,
+                            'optiontype' => '4',
+                            'qtyminimum' => '1',
+                            'qtymaximum' => '10',
+                            'order' => '',
+                            'hidden' => '',
+                        ]
+                    );
+
+            $tblpricing_rel_id = Capsule::table('tblproductconfigoptionssub')->insertGetId(
+                        [
+                            'configid' => $configid,
+                            'optionname' => '',
+                            'sortorder' => '',
+                            'hidden' => ''
+                        ]
+                    );            
+            
+            $result = Capsule::table('tblcurrencies')->get();
+            foreach($result as $data)  {
+                $curr_id = $data->id;
+                $curr_code = $data->code;
+                $currenciesarray[$curr_id] = $curr_code;
+            }
+
+            foreach ($currenciesarray as $curr_id => $currency) {
+              Capsule::table('tblpricing')->insertGetId(
+                        [
+                            'type' => 'configoptions',
+                            'currency' => $curr_id,
+                            'relid' =>  $tblpricing_rel_id,
+                            'msetupfee' => '',
+                            'qsetupfee' => '',
+                            'ssetupfee' => '',
+                            'asetupfee' => '',
+                            'bsetupfee' => '',
+                            'tsetupfee' => '',
+                            'monthly' => '',
+                            'quarterly' => '',
+                            'semiannually' => '',
+                            'annually' => '',
+                            'biennially' => '',
+                            'triennially' => '',
+                        ]
+                    ); 
+            }
+        }
+        ###########################################
+    }
+}
+
+function nextcloud_unlinkproductconfigoptions($productid) { 
+
+    $addconfigrablegroupname = "nextcloud Storage" . $productid;
+    $chkGroup = Capsule::table('tblproductconfiggroups')->where('name',$addconfigrablegroupname)->count();
+    if($chkGroup!='0') {
+        $query = Capsule::table('tblproductconfiglinks')->select('gid')->where('pid',$productid)->get();    
+        $config_group_id = $query[0]->gid;
+
+        $query2 = Capsule::table('tblproductconfigoptions')->select('id')->where('gid',$config_group_id)->get();    
+        $config_id = $query2[0]->id;   
+
+        $query3 = Capsule::table('tblproductconfigoptionssub')->select('id')->where('configid',$config_id)->get();    
+        $pricing_rel_id = $query3[0]->id;
+        if(!empty($pricing_rel_id)){        
+            Capsule::table('tblpricing')->where('type','configoptions')->where('relid',$pricing_rel_id)->delete();
+        }
+        
+        if(!empty($pricing_rel_id)){    
+            Capsule::table('tblproductconfigoptionssub')->where('id',$config_id)->delete();
+        }
+        
+        if(!empty($pricing_rel_id)){      
+            Capsule::table('tblproductconfigoptions')->where('gid',$config_group_id)->delete();
+        }
+
+        if(!empty($pricing_rel_id)){    
+            Capsule::table('tblproductconfiggroups')->where('id',$config_group_id)->delete();
+        }
+
+        if(!empty($pricing_rel_id)){        
+            Capsule::table('tblproductconfiglinks')->where('gid',$config_group_id)->delete();
+        }
+    }    
+}
+
+################################################################################################
+# 19.02.2015
+
+function nextcloud_addGroupCustomField($productid, $fieldname, $create_manageAdminGroup, $userwithoutgroup, $customgroup, $groups) {    
+    $group = substr($fieldname, strpos($fieldname, ':') + 1);
+    if ($userwithoutgroup || $create_manageAdminGroup) {
+       //$affectedRow = Capsule::table('tblcustomfields')->where('fieldname',$group)->where('fieldtype','dropdown')->where('type','product')->where('relid',$productid)->delete();       
+       $affectedRow = Capsule::delete("delete from tblcustomfields where relid='".$productid."' and type='product' and fieldname like 'Group%' ");
+//        if ($affectedRow == 0) {            
+//            Capsule::table('tblcustomfields')->where('type','product')->where('relid',$productid)->delete();
+//        }
+    } elseif ((!$create_manageAdminGroup && !$userwithoutgroup) && !$customgroup) { 
+//        if (!strpos($fieldname, ":")) {
+        $avail_group_result = Capsule::select("SELECT count(*) as `group_field` FROM `tblcustomfields` WHERE `fieldtype`='dropdown' AND `type`='product' AND `relid`=" . $productid);
+        $avail_group_data = (array) $avail_group_result[0];
+        
+        if ($avail_group_data['group_field'] == 0) {
+            $addfieldname = "Group";
+            $addfieldtype = "dropdown";
+            $addcustomfielddesc = '';
+            $addfieldoptions = implode(",", $groups);
+            $addregexpr = '';
+            $addadminonly = '';
+            $addrequired = 'on';
+            $addshoworder = 'on';
+            $addshowinvoice = '';
+            $addsortorder = '';            
+            
+            Capsule::table('tblcustomfields')->insertGetId(
+                [
+                    'type' => 'product',
+                    'relid' => $productid,
+                    'fieldname' =>  $addfieldname,
+                    'fieldtype' => $addfieldtype,
+                    'description' => $addcustomfielddesc,
+                    'fieldoptions' => $addfieldoptions,
+                    'regexpr' => html_entity_decode($addregexpr),
+                    'adminonly' => $addadminonly,
+                    'required' => $addrequired,
+                    'showorder' => $addshoworder,
+                    'showinvoice' => $addshowinvoice,
+                    'sortorder' => $addsortorder,
+                ]
+            );
+            
+            
+        }
+//        }
+    }    
+}
+
+function nextcloud_remove_utf8bom($text) {
+    $bom = pack('H*', 'EFBBBF');
+    $text = preg_replace("/^$bom/", '', $text);
+    return $text;
+}
+
+function nextcloud_Send($href, $username, $password, $action, $post = array()) {
+    $postdata = http_build_query($post);
+    $ch = curl_init();
+    if (strtoupper($action) == 'POST'):
+        curl_setopt($ch, CURLOPT_POST, true);
+        if ($postdata)
+            curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
+    endif;
+
+    if (strtoupper($action) == 'PUT'):
+        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
+        if ($postdata)
+            curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
+    endif;
+
+    if (strtoupper($action) == 'GET'):
+        curl_setopt($ch, CURLOPT_HTTPGET, true);
+    endif;
+
+    if (strtoupper($action) == 'DELETE'):
+        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
+    endif;
+
+    curl_setopt($ch, CURLOPT_URL, $href);
+    curl_setopt($ch, CURLOPT_USERPWD, $username . ":" . $password);
+    curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept: application/json","OCS-APIRequest: true",'content-type: application/x-www-form-urlencoded'));
+    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
+    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
+    $result_json = curl_exec($ch);
+	curl_close($ch);
+	//print_r($result_json);die();
+    $result_bom = nextcloud_remove_utf8bom($result_json);
+    $result = json_decode($result_bom);
+
+    return($result);
+}
+
+function nextcloud_API_URL($serverSecure, $host, $apiurl, $app_id = NULL, $action = '') {
+    $url = $serverSecure . $host . $apiurl . $app_id . $action . '?format=json';
+    return $url;
+}
+
+
+######################################## Encoding Class ######################################33
+
+class nextcloud_Encoding {
+
+    const ICONV_TRANSLIT = "TRANSLIT";
+    const ICONV_IGNORE = "IGNORE";
+    const WITHOUT_ICONV = "";
+
+    protected static $win1252ToUtf8 = array(
+        128 => "\xe2\x82\xac",
+        130 => "\xe2\x80\x9a",
+        131 => "\xc6\x92",
+        132 => "\xe2\x80\x9e",
+        133 => "\xe2\x80\xa6",
+        134 => "\xe2\x80\xa0",
+        135 => "\xe2\x80\xa1",
+        136 => "\xcb\x86",
+        137 => "\xe2\x80\xb0",
+        138 => "\xc5\xa0",
+        139 => "\xe2\x80\xb9",
+        140 => "\xc5\x92",
+        142 => "\xc5\xbd",
+        145 => "\xe2\x80\x98",
+        146 => "\xe2\x80\x99",
+        147 => "\xe2\x80\x9c",
+        148 => "\xe2\x80\x9d",
+        149 => "\xe2\x80\xa2",
+        150 => "\xe2\x80\x93",
+        151 => "\xe2\x80\x94",
+        152 => "\xcb\x9c",
+        153 => "\xe2\x84\xa2",
+        154 => "\xc5\xa1",
+        155 => "\xe2\x80\xba",
+        156 => "\xc5\x93",
+        158 => "\xc5\xbe",
+        159 => "\xc5\xb8"
+    );
+    protected static $brokenUtf8ToUtf8 = array(
+        "\xc2\x80" => "\xe2\x82\xac",
+        "\xc2\x82" => "\xe2\x80\x9a",
+        "\xc2\x83" => "\xc6\x92",
+        "\xc2\x84" => "\xe2\x80\x9e",
+        "\xc2\x85" => "\xe2\x80\xa6",
+        "\xc2\x86" => "\xe2\x80\xa0",
+        "\xc2\x87" => "\xe2\x80\xa1",
+        "\xc2\x88" => "\xcb\x86",
+        "\xc2\x89" => "\xe2\x80\xb0",
+        "\xc2\x8a" => "\xc5\xa0",
+        "\xc2\x8b" => "\xe2\x80\xb9",
+        "\xc2\x8c" => "\xc5\x92",
+        "\xc2\x8e" => "\xc5\xbd",
+        "\xc2\x91" => "\xe2\x80\x98",
+        "\xc2\x92" => "\xe2\x80\x99",
+        "\xc2\x93" => "\xe2\x80\x9c",
+        "\xc2\x94" => "\xe2\x80\x9d",
+        "\xc2\x95" => "\xe2\x80\xa2",
+        "\xc2\x96" => "\xe2\x80\x93",
+        "\xc2\x97" => "\xe2\x80\x94",
+        "\xc2\x98" => "\xcb\x9c",
+        "\xc2\x99" => "\xe2\x84\xa2",
+        "\xc2\x9a" => "\xc5\xa1",
+        "\xc2\x9b" => "\xe2\x80\xba",
+        "\xc2\x9c" => "\xc5\x93",
+        "\xc2\x9e" => "\xc5\xbe",
+        "\xc2\x9f" => "\xc5\xb8"
+    );
+    protected static $utf8ToWin1252 = array(
+        "\xe2\x82\xac" => "\x80",
+        "\xe2\x80\x9a" => "\x82",
+        "\xc6\x92" => "\x83",
+        "\xe2\x80\x9e" => "\x84",
+        "\xe2\x80\xa6" => "\x85",
+        "\xe2\x80\xa0" => "\x86",
+        "\xe2\x80\xa1" => "\x87",
+        "\xcb\x86" => "\x88",
+        "\xe2\x80\xb0" => "\x89",
+        "\xc5\xa0" => "\x8a",
+        "\xe2\x80\xb9" => "\x8b",
+        "\xc5\x92" => "\x8c",
+        "\xc5\xbd" => "\x8e",
+        "\xe2\x80\x98" => "\x91",
+        "\xe2\x80\x99" => "\x92",
+        "\xe2\x80\x9c" => "\x93",
+        "\xe2\x80\x9d" => "\x94",
+        "\xe2\x80\xa2" => "\x95",
+        "\xe2\x80\x93" => "\x96",
+        "\xe2\x80\x94" => "\x97",
+        "\xcb\x9c" => "\x98",
+        "\xe2\x84\xa2" => "\x99",
+        "\xc5\xa1" => "\x9a",
+        "\xe2\x80\xba" => "\x9b",
+        "\xc5\x93" => "\x9c",
+        "\xc5\xbe" => "\x9e",
+        "\xc5\xb8" => "\x9f"
+    );
+
+    static function toUTF8($text) {
+
+        if (is_array($text)) {
+            foreach ($text as $k => $v) {
+                $text[$k] = self::toUTF8($v);
+            }
+            return $text;
+        } elseif (is_string($text)) {
+
+            if (function_exists('mb_strlen') && ((int) ini_get('mbstring.func_overload')) & 2) {
+                $max = mb_strlen($text, '8bit');
+            } else {
+                $max = strlen($text);
+            }
+
+            $buf = "";
+            for ($i = 0; $i < $max; $i++) {
+                $c1 = $text{$i};
+                if ($c1 >= "\xc0") { //Should be converted to UTF8, if it's not UTF8 already
+                    $c2 = $i + 1 >= $max ? "\x00" : $text{$i + 1};
+                    $c3 = $i + 2 >= $max ? "\x00" : $text{$i + 2};
+                    $c4 = $i + 3 >= $max ? "\x00" : $text{$i + 3};
+                    if ($c1 >= "\xc0" & $c1 <= "\xdf") { //looks like 2 bytes UTF8
+                        if ($c2 >= "\x80" && $c2 <= "\xbf") { //yeah, almost sure it's UTF8 already
+                            $buf .= $c1 . $c2;
+                            $i++;
+                        } else { //not valid UTF8.  Convert it.
+                            $cc1 = (chr(ord($c1) / 64) | "\xc0");
+                            $cc2 = ($c1 & "\x3f") | "\x80";
+                            $buf .= $cc1 . $cc2;
+                        }
+                    } elseif ($c1 >= "\xe0" & $c1 <= "\xef") { //looks like 3 bytes UTF8
+                        if ($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf") { //yeah, almost sure it's UTF8 already
+                            $buf .= $c1 . $c2 . $c3;
+                            $i = $i + 2;
+                        } else { //not valid UTF8.  Convert it.
+                            $cc1 = (chr(ord($c1) / 64) | "\xc0");
+                            $cc2 = ($c1 & "\x3f") | "\x80";
+                            $buf .= $cc1 . $cc2;
+                        }
+                    } elseif ($c1 >= "\xf0" & $c1 <= "\xf7") { //looks like 4 bytes UTF8
+                        if ($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf" && $c4 >= "\x80" && $c4 <= "\xbf") { //yeah, almost sure it's UTF8 already
+                            $buf .= $c1 . $c2 . $c3 . $c4;
+                            $i = $i + 3;
+                        } else { //not valid UTF8.  Convert it.
+                            $cc1 = (chr(ord($c1) / 64) | "\xc0");
+                            $cc2 = ($c1 & "\x3f") | "\x80";
+                            $buf .= $cc1 . $cc2;
+                        }
+                    } else { //doesn't look like UTF8, but should be converted
+                        $cc1 = (chr(ord($c1) / 64) | "\xc0");
+                        $cc2 = (($c1 & "\x3f") | "\x80");
+                        $buf .= $cc1 . $cc2;
+                    }
+                } elseif (($c1 & "\xc0") == "\x80") { // needs conversion
+                    if (isset(self::$win1252ToUtf8[ord($c1)])) { //found in Windows-1252 special cases
+                        $buf .= self::$win1252ToUtf8[ord($c1)];
+                    } else {
+                        $cc1 = (chr(ord($c1) / 64) | "\xc0");
+                        $cc2 = (($c1 & "\x3f") | "\x80");
+                        $buf .= $cc1 . $cc2;
+                    }
+                } else { // it doesn't need conversion
+                    $buf .= $c1;
+                }
+            }
+            return $buf;
+        } else {
+            return $text;
+        }
+    }
+
+    static function toWin1252($text, $option = self::WITHOUT_ICONV) {
+        if (is_array($text)) {
+            foreach ($text as $k => $v) {
+                $text[$k] = self::toWin1252($v, $option);
+            }
+            return $text;
+        } elseif (is_string($text)) {
+            return static::utf8_decode($text, $option);
+        } else {
+            return $text;
+        }
+    }
+
+    static function toISO8859($text) {
+        return self::toWin1252($text);
+    }
+
+    static function toLatin1($text) {
+        return self::toWin1252($text);
+    }
+
+    static function fixUTF8($text, $option = self::WITHOUT_ICONV) {
+        if (is_array($text)) {
+            foreach ($text as $k => $v) {
+                $text[$k] = self::fixUTF8($v, $option);
+            }
+            return $text;
+        }
+
+        $last = "";
+        while ($last <> $text) {
+            $last = $text;
+            $text = self::toUTF8(static::utf8_decode($text, $option));
+        }
+        $text = self::toUTF8(static::utf8_decode($text, $option));
+        return $text;
+    }
+
+    static function UTF8FixWin1252Chars($text) {
+        // If you received an UTF-8 string that was converted from Windows-1252 as it was ISO8859-1
+        // (ignoring Windows-1252 chars from 80 to 9F) use this function to fix it.
+        // See: http://en.wikipedia.org/wiki/Windows-1252
+
+        return str_replace(array_keys(self::$brokenUtf8ToUtf8), array_values(self::$brokenUtf8ToUtf8), $text);
+    }
+
+    static function removeBOM($str = "") {
+        if (substr($str, 0, 3) == pack("CCC", 0xef, 0xbb, 0xbf)) {
+            $str = substr($str, 3);
+        }
+        return $str;
+    }
+
+    public static function normalizeEncoding($encodingLabel) {
+        $encoding = strtoupper($encodingLabel);
+        $encoding = preg_replace('/[^a-zA-Z0-9\s]/', '', $encoding);
+        $equivalences = array(
+            'ISO88591' => 'ISO-8859-1',
+            'ISO8859' => 'ISO-8859-1',
+            'ISO' => 'ISO-8859-1',
+            'LATIN1' => 'ISO-8859-1',
+            'LATIN' => 'ISO-8859-1',
+            'UTF8' => 'UTF-8',
+            'UTF' => 'UTF-8',
+            'WIN1252' => 'ISO-8859-1',
+            'WINDOWS1252' => 'ISO-8859-1'
+        );
+
+        if (empty($equivalences[$encoding])) {
+            return 'UTF-8';
+        }
+
+        return $equivalences[$encoding];
+    }
+
+    public static function encode($encodingLabel, $text) {
+        $encodingLabel = self::normalizeEncoding($encodingLabel);
+        if ($encodingLabel == 'UTF-8')
+            return Encoding::toUTF8($text);
+        if ($encodingLabel == 'ISO-8859-1')
+            return Encoding::toLatin1($text);
+    }
+
+    protected static function utf8_decode($text, $option) {
+        if ($option == self::WITHOUT_ICONV || !function_exists('iconv')) {
+            $o = utf8_decode(
+                    str_replace(array_keys(self::$utf8ToWin1252), array_values(self::$utf8ToWin1252), self::toUTF8($text))
+            );
+        } else {
+            $o = iconv("UTF-8", "Windows-1252" . ($option == self::ICONV_TRANSLIT ? '//TRANSLIT' : ($option == self::ICONV_IGNORE ? '//IGNORE' : '')), $text);
+        }
+        return $o;
+    }
+
+}
+
+?>

+ 28 - 0
whmcs.json

@@ -0,0 +1,28 @@
+{
+  "schema": "1.0",
+  "type": "whmcs-provisioning",
+  "name": "nextcloud",
+  "license": "GPL",
+  "category": "provisioning",
+  "description": {
+    "name": "Nextcloud",
+    "tagline": "Nextcloud Provisioning Module for WHMCS.",
+    "short": "Nextcloud users can be easily provoked with this module. The customer can also reset his Nextcloud password.",
+    "long": "The module allows single-user provisioning of Nextcloud accounts. It implements a simple nextcloud.  hosting for private customers with only one account each. The hosting of corporate environments was deliberately omitted, because they get their own instance (VM) for their nextcloud data."
+  },
+  "logo": {
+    "filename": "logo.png"
+  },
+  "support": {
+    "homepage": "https://www.thurdata.ch/whmcs",
+    "learn_more": "https://www.thurdata.ch/whmcs/#features",
+    "support_url": "https://www.thurdata.ch/support",
+    "docs_url": "https://www.thudata.ch/whmcs/docs"
+  },
+  "authors": [
+    {
+      "name": "Thurdata GmbH",
+      "homepage": "https://www.thurdata.ch/"
+    }
+  ]
+}

BIN
windows.png