PNG  IHDR* pHYs+ IDATx]n#; cdLb Ǚ[at¤_:uP}>!Usă cag޿ ֵNu`ݼTâabO7uL&y^wFٝA"l[|ŲHLN밪4*sG3|Dv}?+y߉{OuOAt4Jj.u]Gz*҉sP'VQKbA1u\`& Af;HWj hsO;ogTu uj7S3/QzUr&wS`M$X_L7r2;aE+ώ%vikDA:dR+%KzƉo>eOth$z%: :{WwaQ:wz%4foɹE[9<]#ERINƻv溂E%P1i01 |Jvҗ&{b?9g=^wζXn/lK::90KwrюO\!ջ3uzuGv^;騢wq<Iatv09:tt~hEG`v;3@MNZD.1]L:{ծI3`L(÷ba")Y.iljCɄae#I"1 `3*Bdz>j<fU40⨬%O$3cGt]j%Fߠ_twJ;ABU8vP3uEԑwQ V:h%))LfraqX-ۿX]v-\9I gl8tzX ]ecm)-cgʒ#Uw=Wlێn(0hPP/ӨtQ“&J35 $=]r1{tLuǮ*i0_;NƝ8;-vݏr8+U-kruȕYr0RnC]*ެ(M:]gE;{]tg(#ZJ9y>utRDRMdr9㪩̞zֹb<ģ&wzJM"iI( .ꮅX)Qw:9,i좜\Ԛi7&N0:asϓc];=ΗOӣ APqz93 y $)A*kVHZwBƺnWNaby>XMN*45~ղM6Nvm;A=jֲ.~1}(9`KJ/V F9[=`~[;sRuk]rєT!)iQO)Y$V ی ۤmzWz5IM Zb )ˆC`6 rRa}qNmUfDsWuˤV{ Pݝ'=Kֳbg,UҘVz2ﴻnjNgBb{? ߮tcsͻQuxVCIY۠:(V뺕 ٥2;t`@Fo{Z9`;]wMzU~%UA蛚dI vGq\r82iu +St`cR.6U/M9IENDB`#!/usr/local/cpanel/3rdparty/bin/perl package scripts::update_freebusy_data; # cpanel - scripts/update_freebusy_data Copyright 2024 cPanel, L.L.C. # All rights reserved. # copyright@cpanel.net http://cpanel.net # This code is subject to the cPanel license. Unauthorized copying is prohibited use cPstrict; use Cpanel::Config::Users (); use Cpanel::DAV::CaldavCarddav (); use Cpanel::DAV::Metadata (); use Cpanel::PwCache (); use Cpanel::Slurper (); use Whostmgr::Email (); use Try::Tiny; use parent qw( Cpanel::HelpfulScript ); use constant _OPTIONS => ('user=s'); =encoding utf-8 =head1 NAME update_freebusy_data =head1 USAGE scripts/update_freebusy_data [--user] =head1 DESCRIPTION This script updates free-busy information based on what is currently in either: * All users' calendar collections * The specified user's collections. =cut # NOTE: This script is an "error steamroller". In almost every circumstance # this tolerates even the most heinous of errors # We get a list of all cpanel users, if they have a ~/.caldav/ dir, we load the metadata for each email user underneath # to get a list of the VCALENDARs, then proceeed to go through all of their event files to extract the event start and end times, # timezone/TZID, RRULEs, and save them in a hash, which is serialized into a json file under each principal email user. # Get data back out: # my $fb_data_hr = load_freebusy_data("/home/$sysuser/.caldav/$principaluser/.freebusy.json"); # print Dumper( $fb_data_hr ); # This script can take a single argument which is the username of the system account (as is called by restorepkg via Whostmgr/Transfers/Systems/NativeDAV.pm # Otherwise it will process all users on the server. exit __PACKAGE__->new(@ARGV)->run() unless caller(); sub run ($self) { if ( $< != 0 ) { print STDERR "You must be root to run this script!"; return 1; } my $user2update = $self->getopt('user'); my @users2update = map { $_, @{ Whostmgr::Email::list_pops_for($_) } } length $user2update ? ($user2update) : Cpanel::Config::Users::getcpusers(); my $cpuser; my $user_homedir; my %fb_data; foreach my $user (@users2update) { print "Processing Free/Busy data for $user...\n" if $ENV{'CPANEL_DEBUG_LEVEL'}; my $is_webmail_user = index( $user, '@' ) != -1; if ( !$is_webmail_user ) { $cpuser = $user; $user_homedir = scalar( ( Cpanel::PwCache::getpwnam($cpuser) )[7] ); } next if !$user_homedir || !-d $user_homedir . '/.caldav/'; my $principal_base_path = $user_homedir . '/.caldav/' . $user . '/'; my $fb_full_path = $principal_base_path . '.freebusy.json'; # define the hash we will use to store all time slots from all events and all calendar collections under this $user my %fb_data; # load metadata and find VCALENDARS my $metadata_hr = Cpanel::DAV::Metadata->new( 'homedir' => $user_homedir, 'user' => $user, )->load(); foreach my $collection ( keys %{$metadata_hr} ) { # Shared collections get updated on the relevant user's pass next if $collection =~ m'///'; next if !defined( $metadata_hr->{$collection}{'type'} ) || $metadata_hr->{$collection}{'type'} ne 'VCALENDAR'; my $col_dh; if ( !opendir( $col_dh, $principal_base_path . $collection ) ) { print STDERR "Could not open collection directory ${principal_base_path}${collection} : $!\n"; next; } # this assumes .ics extension, and so far 100% have been that, # but something to keep in mind. case agnostic despite 100% # being lc from the caldav clients already my @vcards = grep { $_ !~ m/^\./ && $_ =~ m/\.ics$/i } readdir($col_dh); closedir $col_dh; foreach my $vcard (@vcards) { my $vcard_path = $principal_base_path . $collection . '/' . $vcard; next if !-e $vcard_path; my $raw_ics_data; try { $raw_ics_data = Cpanel::Slurper::read($vcard_path); my $events_ar = Cpanel::DAV::CaldavCarddav::get_events_info( undef, \$raw_ics_data ); my $fbdata_col_hr = Cpanel::DAV::CaldavCarddav::get_freebusy_data_from_parsed_ics($events_ar); foreach my $uid ( keys %{$fbdata_col_hr} ) { $fb_data{$collection}{$uid} = $fbdata_col_hr->{$uid}; $fb_data{$collection}{$uid}{'file'} = $vcard; # because some clients like to use names other than the UID.. } } catch { print STDERR $_; }; } } # Save the freebusy data for the user. if ( keys %fb_data ) { print "Saving updated freebusy data for $user..\n" if $ENV{'CPANEL_DEBUG_LEVEL'}; Cpanel::DAV::CaldavCarddav::save_freebusy_data( $fb_full_path, $cpuser, \%fb_data ); } } print "Done!\n" if $ENV{'CPANEL_DEBUG_LEVEL'}; return 0; } 1;