function get() { if (!local_channel()) { notice(t('Permission denied.') . EOL); return; } $channel = \App::get_channel(); $is_owner = local_channel() && local_channel() == $channel['channel_id']; //check for updated items and remove them require_once 'include/sharedwithme.php'; apply_updates(); //drop single file - localuser if (argc() > 2 && argv(2) === 'drop') { $id = intval(argv(1)); q("DELETE FROM item WHERE id = %d AND uid = %d", intval($id), intval(local_channel())); goaway(z_root() . '/sharedwithme'); } //drop all files - localuser if (argc() > 1 && argv(1) === 'dropall') { q("DELETE FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d", dbesc(ACTIVITY_POST), dbesc(ACTIVITY_OBJ_FILE), intval(local_channel())); goaway(z_root() . '/sharedwithme'); } //list files $r = q("SELECT id, uid, object, item_unseen FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d AND owner_xchan != '%s'", dbesc(ACTIVITY_POST), dbesc(ACTIVITY_OBJ_FILE), intval(local_channel()), dbesc($channel['channel_hash'])); $items = array(); $ids = ''; if ($r) { foreach ($r as $rr) { $object = json_decode($rr['object'], true); $item = array(); $item['id'] = $rr['id']; $item['objfiletype'] = $object['filetype']; $item['objfiletypeclass'] = getIconFromType($object['filetype']); $item['objurl'] = rawurldecode(get_rel_link($object['link'], 'alternate')) . '?f=&zid=' . $channel['xchan_addr']; $item['objfilename'] = $object['filename']; $item['objfilesize'] = userReadableSize($object['filesize']); $item['objedited'] = $object['edited']; $item['unseen'] = $rr['item_unseen']; $items[] = $item; if ($item['unseen'] > 0) { $ids .= " '" . $rr['id'] . "',"; } } } if ($ids) { //remove trailing , $ids = rtrim($ids, ","); q("UPDATE item SET item_unseen = 0 WHERE id IN ( {$ids} ) AND uid = %d", intval(local_channel())); } $o = profile_tabs($a, $is_owner, $channel['channel_address']); $o .= replace_macros(get_markup_template('sharedwithme.tpl'), array('$header' => t('Files: shared with me'), '$name' => t('Name'), '$label_new' => t('NEW'), '$size' => t('Size'), '$lastmod' => t('Last Modified'), '$dropall' => t('Remove all files'), '$drop' => t('Remove this file'), '$items' => $items)); return $o; }
/** * @brief Creates a form to add new folders and upload files. * * @param \Sabre\DAV\INode $node * @param string &$output */ public function htmlActionsPanel(DAV\INode $node, &$output) { if (!$node instanceof DAV\ICollection) { return; } // We also know fairly certain that if an object is a non-extended // SimpleCollection, we won't need to show the panel either. if (get_class($node) === 'Sabre\\DAV\\SimpleCollection') { return; } // Storage and quota for the account (all channels of the owner of this directory)! $limit = engr_units_to_bytes(service_class_fetch($owner, 'attach_upload_limit')); $r = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d", intval($this->auth->channel_account_id)); $used = $r[0]['total']; if ($used) { $quotaDesc = t('You are using %1$s of your available file storage.'); $quotaDesc = sprintf($quotaDesc, userReadableSize($used)); } if ($limit && $used) { $quotaDesc = t('You are using %1$s of %2$s available file storage. (%3$s%)'); $quotaDesc = sprintf($quotaDesc, userReadableSize($used), userReadableSize($limit), round($used / $limit, 1) * 100); } // prepare quota for template $quota = array(); $quota['used'] = $used; $quota['limit'] = $limit; $quota['desc'] = $quotaDesc; $quota['warning'] = $limit && round($used / $limit, 1) * 100 >= 90 ? t('WARNING:') : ''; // 10485760 bytes = 100MB $output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array('$folder_header' => t('Create new folder'), '$folder_submit' => t('Create'), '$upload_header' => t('Upload file'), '$upload_submit' => t('Upload'), '$quota' => $quota)); }
function theme_attachments(&$item) { $arr = json_decode_plus($item['attach']); if (is_array($arr) && count($arr)) { $attaches = array(); foreach ($arr as $r) { $icon = getIconFromType($r['type']); $label = $r['title'] ? urldecode(htmlspecialchars($r['title'], ENT_COMPAT, 'UTF-8')) : t('Unknown Attachment'); //some feeds provide an attachment where title an empty space if ($label == ' ') { $label = t('Unknown Attachment'); } $title = t('Size') . ' ' . ($r['length'] ? userReadableSize($r['length']) : t('unknown')); require_once 'include/identity.php'; if (is_foreigner($item['author_xchan'])) { $url = $r['href']; } else { $url = z_root() . '/magic?f=&hash=' . $item['author_xchan'] . '&dest=' . $r['href'] . '/' . $r['revision']; } //$s .= '<a href="' . $url . '" title="' . $title . '" class="attachlink" >' . $icon . '</a>'; $attaches[] = array('label' => $label, 'url' => $url, 'icon' => $icon, 'title' => $title); } $s = replace_macros(get_markup_template('item_attach.tpl'), array('$attaches' => $attaches)); } return $s; }
/** * @brief Creates a new file in the directory. * * Data will either be supplied as a stream resource, or in certain cases * as a string. Keep in mind that you may have to support either. * * After successful creation of the file, you may choose to return the ETag * of the new file here. * * @throw \Sabre\DAV\Exception\Forbidden * @param string $name Name of the file * @param resource|string $data Initial payload * @return null|string ETag */ public function createFile($name, $data = null) { logger('create file in directory ' . $name, LOGGER_DEBUG); if (!$this->auth->owner_id) { logger('permission denied ' . $name); throw new DAV\Exception\Forbidden('Permission denied.'); } if (!perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) { logger('permission denied ' . $name); throw new DAV\Exception\Forbidden('Permission denied.'); } $mimetype = z_mime_content_type($name); $c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1", intval($this->auth->owner_id)); if (!$c) { logger('no channel'); throw new DAV\Exception\Forbidden('Permission denied.'); } $filesize = 0; $hash = random_string(); $f = 'store/' . $this->auth->owner_nick . '/' . ($this->os_path ? $this->os_path . '/' : '') . $hash; $direct = null; if ($this->folder_hash) { $r = q("select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1", dbesc($this->folder_hash), intval($c[0]['channel_id'])); if ($r) { $direct = $r[0]; } } if ($direct && ($direct['allow_cid'] || $direct['allow_gid'] || $direct['deny_cid'] || $direct['deny_gid'])) { $allow_cid = $direct['allow_cid']; $allow_gid = $direct['allow_gid']; $deny_cid = $direct['deny_cid']; $deny_gid = $direct['deny_gid']; } else { $allow_cid = $c[0]['channel_allow_cid']; $allow_gid = $c[0]['channel_allow_gid']; $deny_cid = $c[0]['channel_deny_cid']; $deny_gid = $c[0]['channel_deny_gid']; } $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, folder, os_storage, filetype, filesize, revision, is_photo, content, created, edited, allow_cid, allow_gid, deny_cid, deny_gid )\n\t\t\tVALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", intval($c[0]['channel_account_id']), intval($c[0]['channel_id']), dbesc($hash), dbesc($this->auth->observer), dbesc($name), dbesc($this->folder_hash), intval(1), dbesc($mimetype), intval($filesize), intval(0), intval($is_photo), dbesc($f), dbesc(datetime_convert()), dbesc(datetime_convert()), dbesc($allow_cid), dbesc($allow_gid), dbesc($deny_cid), dbesc($deny_gid)); // returns the number of bytes that were written to the file, or FALSE on failure $size = file_put_contents($f, $data); // delete attach entry if file_put_contents() failed if ($size === false) { logger('file_put_contents() failed to ' . $f); attach_delete($c[0]['channel_id'], $hash); return; } // returns now $edited = datetime_convert(); $is_photo = 0; $x = @getimagesize($f); logger('getimagesize: ' . print_r($x, true), LOGGER_DATA); if ($x && ($x[2] === IMAGETYPE_GIF || $x[2] === IMAGETYPE_JPEG || $x[2] === IMAGETYPE_PNG)) { $is_photo = 1; } // updates entry with filesize and timestamp $d = q("UPDATE attach SET filesize = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d", dbesc($size), intval($is_photo), dbesc($edited), dbesc($hash), intval($c[0]['channel_id'])); // update the folder's lastmodified timestamp $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d", dbesc($edited), dbesc($this->folder_hash), intval($c[0]['channel_id'])); $maxfilesize = get_config('system', 'maxfilesize'); if ($maxfilesize && $size > $maxfilesize) { attach_delete($c[0]['channel_id'], $hash); return; } // check against service class quota $limit = engr_units_to_bytes(service_class_fetch($c[0]['channel_id'], 'attach_upload_limit')); if ($limit !== false) { $x = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d ", intval($c[0]['channel_account_id'])); if ($x && $x[0]['total'] + $size > $limit) { logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . userReadableSize($limit)); attach_delete($c[0]['channel_id'], $hash); return; } } if ($is_photo) { $album = ''; if ($this->folder_hash) { $f1 = q("select filename from attach WHERE hash = '%s' AND uid = %d", dbesc($this->folder_hash), intval($c[0]['channel_id'])); if ($f1) { $album = $f1[0]['filename']; } } require_once 'include/photos.php'; $args = array('resource_id' => $hash, 'album' => $album, 'os_path' => $f, 'filename' => $name, 'getimagesize' => $x, 'directory' => $direct); $p = photo_upload($c[0], \App::get_observer(), $args); } $sync = attach_export_data($c[0], $hash); if ($sync) { build_sync_packet($c[0]['channel_id'], array('file' => array($sync))); } }
/** * @brief Some PHP configuration checks. * * @todo Change how we display such informational text. Add more description * how to change them. * * @param[out] array &$checks */ function check_phpconfig(&$checks) { require_once 'include/environment.php'; $help = ''; $result = getPhpiniUploadLimits(); $help = sprintf(t('Your max allowed total upload size is set to %s. Maximum size of one file to upload is set to %s. You are allowed to upload up to %d files at once.'), userReadableSize($result['post_max_size']), userReadableSize($result['max_upload_filesize']), $result['max_file_uploads']); $help .= '<br>' . t('You can adjust these settings in the servers php.ini.'); check_add($checks, t('PHP upload limits'), true, false, $help); }
/** * @brief Creates the directory listing for the given path. * * @param string $path which should be displayed */ public function generateDirectoryIndex($path) { // (owner_id = channel_id) is visitor owner of this directory? $is_owner = local_channel() && $this->auth->owner_id == local_channel() ? true : false; if ($this->auth->getTimezone()) { date_default_timezone_set($this->auth->getTimezone()); } require_once 'include/conversation.php'; require_once 'include/text.php'; if ($this->auth->owner_nick) { $html = profile_tabs(get_app(), $is_owner ? true : false, $this->auth->owner_nick); } $files = $this->server->getPropertiesForPath($path, array('{DAV:}displayname', '{DAV:}resourcetype', '{DAV:}getcontenttype', '{DAV:}getcontentlength', '{DAV:}getlastmodified'), 1); $parent = $this->server->tree->getNodeForPath($path); $parentpath = array(); // only show parent if not leaving /cloud/; TODO how to improve this? if ($path && $path != "cloud") { list($parentUri) = DAV\URLUtil::splitPath($path); $fullPath = DAV\URLUtil::encodePath($this->server->getBaseUri() . $parentUri); $parentpath['icon'] = $this->enableAssets ? '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl('icons/parent' . $this->iconExtension) . '" width="24" alt="' . t('parent') . '"></a>' : ''; $parentpath['path'] = $fullPath; } $f = array(); foreach ($files as $file) { $ft = array(); $type = null; // This is the current directory, we can skip it if (rtrim($file['href'], '/') == $path) { continue; } list(, $name) = DAV\URLUtil::splitPath($file['href']); if (isset($file[200]['{DAV:}resourcetype'])) { $type = $file[200]['{DAV:}resourcetype']->getValue(); // resourcetype can have multiple values if (!is_array($type)) { $type = array($type); } foreach ($type as $k => $v) { // Some name mapping is preferred switch ($v) { case '{DAV:}collection': $type[$k] = t('Collection'); break; case '{DAV:}principal': $type[$k] = t('Principal'); break; case '{urn:ietf:params:xml:ns:carddav}addressbook': $type[$k] = t('Addressbook'); break; case '{urn:ietf:params:xml:ns:caldav}calendar': $type[$k] = t('Calendar'); break; case '{urn:ietf:params:xml:ns:caldav}schedule-inbox': $type[$k] = t('Schedule Inbox'); break; case '{urn:ietf:params:xml:ns:caldav}schedule-outbox': $type[$k] = t('Schedule Outbox'); break; case '{http://calendarserver.org/ns/}calendar-proxy-read': $type[$k] = 'Proxy-Read'; break; case '{http://calendarserver.org/ns/}calendar-proxy-write': $type[$k] = 'Proxy-Write'; break; } } $type = implode(', ', $type); } // If no resourcetype was found, we attempt to use // the contenttype property if (!$type && isset($file[200]['{DAV:}getcontenttype'])) { $type = $file[200]['{DAV:}getcontenttype']; } if (!$type) { $type = t('Unknown'); } $size = isset($file[200]['{DAV:}getcontentlength']) ? (int) $file[200]['{DAV:}getcontentlength'] : ''; $lastmodified = isset($file[200]['{DAV:}getlastmodified']) ? $file[200]['{DAV:}getlastmodified']->getTime()->format('Y-m-d H:i:s') : ''; $fullPath = DAV\URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path ? $path . '/' : '') . $name, '/')); $displayName = isset($file[200]['{DAV:}displayname']) ? $file[200]['{DAV:}displayname'] : $name; $displayName = $this->escapeHTML($displayName); $type = $this->escapeHTML($type); $icon = ''; if ($this->enableAssets) { $node = $this->server->tree->getNodeForPath(($path ? $path . '/' : '') . $name); foreach (array_reverse($this->iconMap) as $class => $iconName) { if ($node instanceof $class) { $icon = '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl($iconName . $this->iconExtension) . '" alt="" width="24"></a>'; break; } } } $parentHash = ''; $owner = $this->auth->owner_id; $splitPath = split('/', $fullPath); if (count($splitPath) > 3) { for ($i = 3; $i < count($splitPath); $i++) { $attachName = urldecode($splitPath[$i]); $attachHash = $this->findAttachHash($owner, $parentHash, $attachName); $parentHash = $attachHash; } } $attachIcon = ""; // "<a href=\"attach/".$attachHash."\" title=\"".$displayName."\"><i class=\"icon-download\"></i></a>"; // put the array for this file together $ft['attachId'] = $this->findAttachIdByHash($attachHash); $ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->getCurrentUser(); $ft['icon'] = $icon; $ft['attachIcon'] = $size ? $attachIcon : ''; // @todo Should this be an item value, not a global one? $ft['is_owner'] = $is_owner; $ft['fullPath'] = $fullPath; $ft['displayName'] = $displayName; $ft['type'] = $type; $ft['size'] = $size; $ft['sizeFormatted'] = userReadableSize($size); $ft['lastmodified'] = $lastmodified ? datetime_convert('UTC', date_default_timezone_get(), $lastmodified) : ''; $ft['iconFromType'] = getIconFromType($type); $f[] = $ft; } // Storage and quota for the account (all channels of the owner of this directory)! $limit = service_class_fetch($owner, 'attach_upload_limit'); $r = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d", intval($this->auth->channel_account_id)); $used = $r[0]['total']; if ($used) { $quotaDesc = t('%1$s used'); $quotaDesc = sprintf($quotaDesc, userReadableSize($used)); } if ($limit && $used) { $quotaDesc = t('%1$s used of %2$s (%3$s%)'); $quotaDesc = sprintf($quotaDesc, userReadableSize($used), userReadableSize($limit), round($used / $limit, 1)); } // prepare quota for template $quota = array(); $quota['used'] = $used; $quota['limit'] = $limit; $quota['desc'] = $quotaDesc; $output = ''; if ($this->enablePost) { $this->server->broadcastEvent('onHTMLActionsPanel', array($parent, &$output)); } $html .= replace_macros(get_markup_template('cloud.tpl'), array('$header' => t('Files') . ": " . $this->escapeHTML($path) . "/", '$quota' => $quota, '$total' => t('Total'), '$actionspanel' => $output, '$shared' => t('Shared'), '$create' => t('Create'), '$upload' => t('Upload'), '$is_owner' => $is_owner, '$parentpath' => $parentpath, '$entries' => $f, '$name' => t('Name'), '$type' => t('Type'), '$size' => t('Size'), '$lastmod' => t('Last Modified'), '$parent' => t('parent'), '$edit' => t('Edit'), '$delete' => t('Delete'), '$nick' => $this->auth->getCurrentUser())); $a = get_app(); $a->page['content'] = $html; load_pdl($a); $theme_info_file = "view/theme/" . current_theme() . "/php/theme.php"; if (file_exists($theme_info_file)) { require_once $theme_info_file; if (function_exists(str_replace('-', '_', current_theme()) . '_init')) { $func = str_replace('-', '_', current_theme()) . '_init'; $func($a); } } construct_page($a); }
/** * @brief Creates a form to add new folders and upload files. * * @param \Sabre\DAV\INode $node * @param string &$output */ public function htmlActionsPanel(DAV\INode $node, &$output, $path) { if (!$node instanceof DAV\ICollection) { return; } // We also know fairly certain that if an object is a non-extended // SimpleCollection, we won't need to show the panel either. if (get_class($node) === 'Sabre\\DAV\\SimpleCollection') { return; } require_once 'include/acl_selectors.php'; $aclselect = null; $lockstate = ''; if ($this->auth->owner_id) { $channel = channelx_by_n($this->auth->owner_id); if ($channel) { $acl = new \Zotlabs\Access\AccessList($channel); $channel_acl = $acl->get(); $lockstate = $acl->is_private() ? 'lock' : 'unlock'; $aclselect = local_channel() == $this->auth->owner_id ? populate_acl($channel_acl, false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_storage')) : ''; } } // Storage and quota for the account (all channels of the owner of this directory)! $limit = engr_units_to_bytes(service_class_fetch($owner, 'attach_upload_limit')); $r = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d", intval($this->auth->channel_account_id)); $used = $r[0]['total']; if ($used) { $quotaDesc = t('You are using %1$s of your available file storage.'); $quotaDesc = sprintf($quotaDesc, userReadableSize($used)); } if ($limit && $used) { $quotaDesc = t('You are using %1$s of %2$s available file storage. (%3$s%)'); $quotaDesc = sprintf($quotaDesc, userReadableSize($used), userReadableSize($limit), round($used / $limit, 1) * 100); } // prepare quota for template $quota = array(); $quota['used'] = $used; $quota['limit'] = $limit; $quota['desc'] = $quotaDesc; $quota['warning'] = $limit && round($used / $limit, 1) * 100 >= 90 ? t('WARNING:') : ''; // 10485760 bytes = 100MB $path = trim(str_replace('cloud/' . $this->auth->owner_nick, '', $path), '/'); $output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array('$folder_header' => t('Create new folder'), '$folder_submit' => t('Create'), '$upload_header' => t('Upload file'), '$upload_submit' => t('Upload'), '$quota' => $quota, '$channick' => $this->auth->owner_nick, '$aclselect' => $aclselect, '$allow_cid' => acl2json($channel_acl['allow_cid']), '$allow_gid' => acl2json($channel_acl['allow_gid']), '$deny_cid' => acl2json($channel_acl['deny_cid']), '$deny_gid' => acl2json($channel_acl['deny_gid']), '$lockstate' => $lockstate, '$return_url' => \App::$cmd, '$path' => $path, '$folder' => find_folder_hash_by_path($this->auth->owner_id, $path), '$dragdroptext' => t('Drop files here to immediately upload'))); }
/** * @brief Updates the data of the file. * * @param resource $data * @return void */ public function put($data) { logger('put file: ' . basename($this->name), LOGGER_DEBUG); $size = 0; // @todo only 3 values are needed $c = q("SELECT * FROM channel WHERE channel_id = %d AND channel_removed = 0 LIMIT 1", intval($this->auth->owner_id)); $is_photo = false; $album = ''; $r = q("SELECT flags, folder, os_storage, filename, is_photo FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", dbesc($this->data['hash']), intval($c[0]['channel_id'])); if ($r) { if (intval($r[0]['os_storage'])) { $d = q("select folder, content from attach where hash = '%s' and uid = %d limit 1", dbesc($this->data['hash']), intval($c[0]['channel_id'])); if ($d) { if ($d[0]['folder']) { $f1 = q("select * from attach where is_dir = 1 and hash = '%s' and uid = %d limit 1", dbesc($d[0]['folder']), intval($c[0]['channel_id'])); if ($f1) { $album = $f1[0]['filename']; $direct = $f1[0]; } } $fname = dbunescbin($d[0]['content']); if (strpos($fname, 'store') === false) { $f = 'store/' . $this->auth->owner_nick . '/' . $fname; } else { $f = $fname; } // @todo check return value and set $size directly @file_put_contents($f, $data); $size = @filesize($f); logger('filename: ' . $f . ' size: ' . $size, LOGGER_DEBUG); } $gis = @getimagesize($f); logger('getimagesize: ' . print_r($gis, true), LOGGER_DATA); if ($gis && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) { $is_photo = 1; } } else { // this shouldn't happen any more $r = q("UPDATE attach SET content = '%s' WHERE hash = '%s' AND uid = %d", dbescbin(stream_get_contents($data)), dbesc($this->data['hash']), intval($this->data['uid'])); $r = q("SELECT length(content) AS fsize FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", dbesc($this->data['hash']), intval($this->data['uid'])); if ($r) { $size = $r[0]['fsize']; } } } // returns now() $edited = datetime_convert(); $d = q("UPDATE attach SET filesize = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d", dbesc($size), intval($is_photo), dbesc($edited), dbesc($this->data['hash']), intval($c[0]['channel_id'])); if ($is_photo) { require_once 'include/photos.php'; $args = array('resource_id' => $this->data['hash'], 'album' => $album, 'os_path' => $f, 'filename' => $r[0]['filename'], 'getimagesize' => $gis, 'directory' => $direct); $p = photo_upload($c[0], \App::get_observer(), $args); } // update the folder's lastmodified timestamp $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d", dbesc($edited), dbesc($r[0]['folder']), intval($c[0]['channel_id'])); // @todo do we really want to remove the whole file if an update fails // because of maxfilesize or quota? // There is an Exception "InsufficientStorage" or "PaymentRequired" for // our service class from SabreDAV we could use. $maxfilesize = get_config('system', 'maxfilesize'); if ($maxfilesize && $size > $maxfilesize) { attach_delete($c[0]['channel_id'], $this->data['hash']); return; } $limit = engr_units_to_bytes(service_class_fetch($c[0]['channel_id'], 'attach_upload_limit')); if ($limit !== false) { $x = q("select sum(filesize) as total from attach where aid = %d ", intval($c[0]['channel_account_id'])); if ($x && $x[0]['total'] + $size > $limit) { logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . userReadableSize($limit)); attach_delete($c[0]['channel_id'], $this->data['hash']); return; } } $sync = attach_export_data($c[0], $this->data['hash']); if ($sync) { build_sync_packet($c[0]['channel_id'], array('file' => array($sync))); } }